home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / vbdatabs / strdbt.cpp < prev    next >
C/C++ Source or Header  |  1999-03-28  |  89KB  |  3,242 lines

  1. // ------------------------------- //
  2. // -------- Start of File -------- //
  3. // ------------------------------- //
  4. // ----------------------------------------------------------- // 
  5. // C++ Source Code File Name: strdbt.cpp 
  6. // Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
  7. // Produced By: Doug Gaer  
  8. // File Creation Date: 09/18/1997  
  9. // Date Last Modified: 03/29/1999
  10. // Copyright (c) 1997 Douglas M. Gaer
  11. // ----------------------------------------------------------- // 
  12. // ------------- Program Description and Details ------------- // 
  13. // ----------------------------------------------------------- // 
  14. /*
  15. The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
  16. All those who put this code or its derivatives in a commercial
  17. product MUST mention this copyright in their documentation for
  18. users of the products in which this code or its derivative
  19. classes are used. Otherwise, you have the freedom to redistribute
  20. verbatim copies of this source code, adapt it to your specific
  21. needs, or improve the code and release your improvements to the
  22. public provided that the modified files carry prominent notices
  23. stating that you changed the files and the date of any change.
  24.  
  25. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
  26. THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
  27. IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
  28. YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
  29. CORRECTION.
  30.  
  31. The string database is a general-purpose object-oriented
  32. database. This version is designed to work with a terminal
  33. interface.
  34.  
  35. - Modify "dbconfig.h" file to customize the database
  36. - Modify "dbvers.h" file to uniquely identify the database
  37. - Modify "dbtcfg.h" file to customize this program
  38. - Modify "version.h" file to report changes and fixes
  39. */
  40. // ----------------------------------------------------------- // 
  41. #include <fstream.h> // Using ofstream to print to a text file
  42. #include "strdb_sh.h"
  43. #include "terminal.h"
  44. #include "config.h"
  45. #include "timer.h"
  46. #include "strutil.h"
  47. #include "asprint.h"
  48. #include "pscript.h"
  49. #include "vbdstats.h"
  50. #include "btwalker.h"
  51. #include "htmldrv.h"
  52.  
  53. // Application specific include files
  54. #include "version.h"
  55. #include "dbconfig.h"
  56. #include "dbtcfg.h"
  57.  
  58. static POD *DB;                // Global database pointer
  59. const int KeyBuf = 25;         // Users input limit per string
  60. const int CBuf = 81;           // Input limit for comments
  61. const int StringOffset = 15;   // Display output limit per string
  62. const int IntOffset = 8;       // Display output limit per number
  63. const char *WildCard = "*";    // Used for wild card searches 
  64. const int retrys = 3;          // Times to retry user input operations
  65.  
  66. // Define configurable parameters
  67. int CacheSize = 15;  // Memory cache size for the index file
  68. int AdminRights = 0; // Define user privileges 
  69.  
  70. // Define file access modes used in the application
  71. VBDFile::AccessMode RWMode = VBDFile::READWRITE;
  72. VBDFile::AccessMode ROMode = VBDFile::READONLY;
  73.  
  74. // Menu menu setup
  75. typedef void (*MMF) (); // Pointer to (M)ain (M)enu (F)unctions
  76. const int MMSelections = 6; // Main menu selections
  77.  
  78. // Main menu functions
  79. void Exit();
  80. void ISRMenu();     // Insertion/Removal menu
  81. void FindMenu();    // Query menu
  82. void DisplayMenu(); // Display menu
  83. void FileMenu();    // File operations menu
  84. void PrintMenu();   // Print menu
  85.  
  86. const char *mainmenu[MMSelections] = {
  87.   "(0) - Exit this program",
  88.   "(1) - Add, Remove, or Change items in the database",
  89.   "(2) - Find items in the database",
  90.   "(3) - Display items in the database",
  91.   "(4) - File Operations",
  92.   "(5) - Print Menu"
  93. };
  94.  
  95. MMF MMFunctions[MMSelections] = {
  96.   &Exit,
  97.   &ISRMenu,
  98.   &FindMenu,
  99.   &DisplayMenu,
  100.   &FileMenu,
  101.   &PrintMenu
  102. };
  103.  
  104. // Insertion/Removal menu setup
  105. typedef void (*ISRMF) (); // Pointer to (A)dd (M)enu (F)unctions 
  106. const char *ISRMTitle = "--------- DATABASE INSERTION/REMOVAL MENU ---------";
  107. const int ISRMSelections = 4; // Insertion/Removal menu selections
  108.  
  109. // Insertion/Removal menu functions
  110. void Return();
  111. void Add();
  112. void Change();
  113. void Remove();
  114.  
  115. const char *isrmenu[ISRMSelections] = {
  116.   "(0) - Return to main menu",
  117.   "(1) - Add items to the database",
  118.   "(2) - Change an item in the database",
  119.   "(3) - Remove an item from the database"
  120. };
  121.  
  122. ISRMF ISRMFunctions[ISRMSelections] = {
  123.   &Return,
  124.   &Add,
  125.   &Change,
  126.   &Remove
  127. };
  128.  
  129. // Find menu setup
  130. typedef void (*FMF) (); // Pointer to (F)ind (M)enu (F)unctions 
  131. const char *FMTitle = "---------- DATABASE QUERY MENU ----------";
  132. const int FMSelections = 10; // Find menu selections
  133.  
  134. // Find menu functions
  135. void Return();
  136. void FindByKeyName(); 
  137. void FindByM2Name(); 
  138. void FindByM3Name(); 
  139. void FindByM4Name(); 
  140. void FindByM5Name(); 
  141. void FindByM6Name(); 
  142. void FindByM7Name(); 
  143. void FindByM8Name();
  144. void FindByComments();
  145.  
  146. FMF FMFunctions[FMSelections] = {
  147.   &Return,
  148.   &FindByKeyName,
  149.   &FindByM2Name,
  150.   &FindByM3Name,
  151.   &FindByM4Name,
  152.   &FindByM5Name,
  153.   &FindByM6Name,
  154.   &FindByM7Name,
  155.   &FindByM8Name,
  156.   &FindByComments
  157. };
  158.  
  159. // Display menu setup
  160. typedef void (*DMF) (); // Pointer to (D)isplay (M)enu (F)unctions 
  161. const char *DMTitle = "---------- DATABASE DISPLAY MENU ----------";
  162. const int DMSelections = 3; // Display menu selections
  163.  
  164. // Display menu functions
  165. void DisplayLBL(); // Display all objects line by line
  166. void DisplayAll(); // Display all objects one at a time
  167.  
  168. const char *displaymenu[DMSelections] = {
  169.   "(0) - Return to main menu",
  170.   "(1) - Display all items line by line",
  171.   "(2) - Display all items one a time"
  172. };
  173.  
  174. DMF DMFunctions[DMSelections] = {
  175.   &Return,
  176.   &DisplayLBL,
  177.   &DisplayAll
  178. };
  179.  
  180. // File operations menu setup
  181. typedef void (*FOMF) (); // Pointer to (F)ile (M)enu (F)unctions 
  182. const char *FOMTitle = "---------- DATABASE FILE OPERATIONS MENU ----------";
  183. const int FOMSelections = 9; // File operations menu selections
  184.  
  185. // File operations menu functions
  186. void FileStats();
  187. void ExportToASCII();
  188. void ImportFromASCII();
  189. void BackUp();
  190. void Merge();
  191. void CreateTemplate();
  192. void CompareIndexFile();
  193. void RebuildIndexFile();
  194.  
  195. const char *filemenu[FOMSelections] = {
  196.   "(0) - Return to main menu",
  197.   "(1) - Display Variable Block Database statistics",
  198.   "(2) - Export to ASCII file (delimited by tabs)",
  199.   "(3) - Import ASCII file (delimited by tabs)",
  200.   "(4) - Backup the database to another file",
  201.   "(5) - Merge the contents of another database file",
  202.   "(6) - Create a template for an import file",
  203.   "(7) - Compare the index file to the data file",
  204.   "(8) - Rebuild the index file" 
  205. };
  206.  
  207. FOMF FOMFunctions[FOMSelections] = {
  208.   &Return,
  209.   &FileStats,
  210.   &ExportToASCII,
  211.   &ImportFromASCII,
  212.   &BackUp,
  213.   &Merge,
  214.   &CreateTemplate,
  215.   &CompareIndexFile,
  216.   &RebuildIndexFile
  217. };
  218.  
  219. // Print menu setup
  220. typedef void (*PMF) (); // Pointer to (P)rint (M)enu (F)unctions 
  221. const char *PMTitle = "---------- DATABASE PRINTING MENU ----------";
  222. const int PMSelections = 6; // Print menu selections
  223.  
  224. // Print menu functions
  225. void ASCIIPrintAll();     // Print database to an ASCII file (abbreviated)
  226. void ASCIIPrintAllLong(); // Print database to an ASCII file (full listing) 
  227. void ASCIIPrintObject();  // Print a single object to an ASCII file
  228. void PostScriptPrint();   // Print database to a PostScript file
  229. void HTMLPrint();         // Print the database to an html file
  230.  
  231. const char *printmenu[PMSelections] = {
  232.   "(0) - Return to main menu",
  233.   "(1) - Print to text file (abbreviated, 80 cols)",
  234.   "(2) - Print to text file (full listing, 132 cols)",
  235.   "(3) - Print a single object to a text file",
  236.   "(4) - Print to PostScript file",
  237.   "(5) - Print to an HTML file"
  238. };
  239.  
  240. PMF PMFunctions[PMSelections] = {
  241.   &Return,
  242.   &ASCIIPrintAll,
  243.   &ASCIIPrintAllLong,
  244.   &ASCIIPrintObject,
  245.   &PostScriptPrint,
  246.   &HTMLPrint
  247. };
  248.  
  249. // Function prototypes for functions use by all menu functions
  250. void AddObject(StrDB &strdb, Coords *p);
  251. void ChangeObject(StrDB &strdb, Coords *p, int adding = 0);
  252. void DisplayObject(StrDB &strdb, Coords *p);
  253. void LineByLine(StrDB &strdb, Coords *p);
  254. void DisplayString(const char *s);
  255. int LoadIndexKeys();
  256.  
  257. // Search functions
  258. void FindBy(const char *MemberName, StrDBItem item);
  259. void StrDBSearch(StrDB &strdb, StrDBItem item, UString &str,
  260.          Coords *p, const char *wildcard = 0);
  261.  
  262. enum PrintMode {
  263.   PORTRAIT,
  264.   LANDSCAPE
  265. };
  266.  
  267. void PrintItemBar(ofstream &stream, int abv = 1);
  268. void PrintLineByLine(StrDB &strdb, ofstream &stream, int abv = 1);
  269. int ASCIIPrint(PrintMode mode);
  270. void PrintObject(StrDB &strdb, Coords *p);
  271. int PrintPSItemBar(ofstream &stream, PostScriptDrv &psdrv,
  272.             int x_offset, int char_offset, int max_len);
  273.  
  274. void MainMenu()
  275. {
  276.   int c;
  277.   Coords *p = new Coords(0, 0);
  278.  
  279.   while(1) {
  280.     p->SetXY(0, 0);
  281.     p->SetX(terminal->Center(MMTitle));
  282.     p->SetY(terminal->ScreenCenter(MMSelections));
  283.     terminal->ClearScreen();
  284.     terminal->Write(MMTitle, p->XPos(), p->YPrev());
  285.  
  286.     for(int i = 0; i < MMSelections; i++)
  287.       terminal->Write(mainmenu[i], p->XPos(), p->YOffset(1));
  288.     
  289.     terminal->Write("Press the number of your selection -> ",
  290.             p->XPos(), p->YOffset(2));
  291.     
  292.     c = terminal->GetChar();
  293.     switch(c) {
  294.       case '0': 
  295.     (*MMFunctions[0]) (); // Call the appropriate menu function
  296.     return;
  297.       case '1':
  298.     (*MMFunctions[1]) (); // Call the appropriate menu function
  299.     break;
  300.       case '2':
  301.     (*MMFunctions[2]) (); // Call the appropriate menu function
  302.     break;
  303.       case '3':
  304.     (*MMFunctions[3]) (); // Call the appropriate menu function
  305.     break;
  306.       case '4':
  307.     (*MMFunctions[4]) (); // Call the appropriate menu function
  308.     break;
  309.       case '5':
  310.     (*MMFunctions[5]) (); // Call the appropriate menu function
  311.     break;
  312.       default:
  313.     break;
  314.     }
  315.   }
  316. }
  317.  
  318. void ISRMenu()
  319. {
  320.   int c;
  321.   Coords *p = new Coords(0, 0);
  322.  
  323.   while(1) {
  324.     p->SetXY(0, 0);
  325.     p->SetX(terminal->Center(ISRMTitle));
  326.     p->SetY(terminal->ScreenCenter(ISRMSelections));
  327.     terminal->ClearScreen();
  328.     terminal->Write(ISRMTitle, p->XPos(), p->YPrev());
  329.  
  330.     for(int i = 0; i < ISRMSelections; i++)
  331.       terminal->Write(isrmenu[i], p->XPos(), p->YOffset(1));
  332.     
  333.     terminal->Write("Press the number of your selection -> ",
  334.             p->XPos(), p->YOffset(2));
  335.     
  336.     c = terminal->GetChar();
  337.     switch(c) {
  338.       case '0': 
  339.     (*ISRMFunctions[0]) (); // Call the appropriate menu function
  340.     return;
  341.       case '1':
  342.     (*ISRMFunctions[1]) (); // Call the appropriate menu function
  343.     break;
  344.       case '2':
  345.     (*ISRMFunctions[2]) (); // Call the appropriate menu function
  346.     break;
  347.       case '3':
  348.     (*ISRMFunctions[3]) (); // Call the appropriate menu function
  349.     break;
  350.       default:
  351.     break;
  352.     }
  353.   }
  354. }
  355.  
  356. void FindMenu()
  357. {
  358.   int c;
  359.   Coords *p = new Coords(0, 0);
  360.  
  361.   while(1) {
  362.     p->SetXY(0, 0);
  363.     p->SetX(terminal->Center(FMTitle));
  364.     p->SetY(terminal->ScreenCenter(FMSelections));
  365.     terminal->ClearScreen();
  366.     terminal->Write(FMTitle, p->XPos(), p->YPrev());
  367.  
  368.     terminal->Write("(0) - Return to main menu", p->XPos(), p->YOffset(1));
  369.     if(KeyName != 0) {
  370.       terminal->Write("(1) - Find by ", p->XPos(), p->YOffset(1));
  371.       terminal->Write(KeyName);
  372.     }
  373.     if(M2Name != 0) {
  374.       terminal->Write("(2) - Find by ", p->XPos(), p->YOffset(1));
  375.       terminal->Write(M2Name);
  376.     }
  377.     if(M3Name != 0) {
  378.       terminal->Write("(3) - Find by ", p->XPos(), p->YOffset(1));
  379.       terminal->Write(M3Name);
  380.     }
  381.     if(M4Name != 0) {
  382.       terminal->Write("(4) - Find by ", p->XPos(), p->YOffset(1));
  383.       terminal->Write(M4Name);
  384.     }
  385.     if(M5Name != 0) {
  386.       terminal->Write("(5) - Find by ", p->XPos(), p->YOffset(1));
  387.       terminal->Write(M5Name);
  388.     }
  389.     if(M6Name != 0) {
  390.       terminal->Write("(6) - Find by ", p->XPos(), p->YOffset(1));
  391.       terminal->Write(M6Name);
  392.     }
  393.     if(M7Name != 0) {
  394.       terminal->Write("(7) - Find by ", p->XPos(), p->YOffset(1));
  395.       terminal->Write(M7Name);
  396.     }
  397.     if(M8Name != 0) {
  398.       terminal->Write("(8) - Find by ", p->XPos(), p->YOffset(1));
  399.       terminal->Write(M8Name);
  400.     }
  401.     if(Comments != 0) {
  402.       terminal->Write("(9) - Find by ", p->XPos(), p->YOffset(1));
  403.       terminal->Write(Comments);
  404.     }
  405.     
  406.     terminal->Write("Press the number of your selection -> ",
  407.             p->XPos(), p->YOffset(2));
  408.     
  409.     c = terminal->GetChar();
  410.     switch(c) {
  411.       case '0': 
  412.     (*FMFunctions[0]) (); // Call the appropriate menu function
  413.     return;
  414.       case '1':
  415.     (*FMFunctions[1]) (); // Call the appropriate menu function
  416.     break;
  417.       case '2':
  418.     (*FMFunctions[2]) (); // Call the appropriate menu function
  419.     break;
  420.       case '3':
  421.     (*FMFunctions[3]) (); // Call the appropriate menu function
  422.     break;
  423.       case '4':
  424.     (*FMFunctions[4]) (); // Call the appropriate menu function
  425.     break;
  426.       case '5':
  427.     (*FMFunctions[5]) (); // Call the appropriate menu function
  428.     break;
  429.       case '6':
  430.     (*FMFunctions[6]) (); // Call the appropriate menu function
  431.     break;
  432.       case '7':
  433.     (*FMFunctions[7]) (); // Call the appropriate menu function
  434.     break;
  435.       case '8':
  436.     (*FMFunctions[8]) (); // Call the appropriate menu function
  437.     break;
  438.       case '9':
  439.     (*FMFunctions[9]) (); // Call the appropriate menu function
  440.     break;
  441.       default:
  442.     break;
  443.     }
  444.   }
  445. }
  446.  
  447. void DisplayMenu()
  448. {
  449.   int c;
  450.   Coords *p = new Coords(0, 0);
  451.  
  452.   while(1) {
  453.     p->SetXY(0, 0);
  454.     p->SetX(terminal->Center(DMTitle));
  455.     p->SetY(terminal->ScreenCenter(DMSelections));
  456.     terminal->ClearScreen();
  457.     terminal->Write(DMTitle, p->XPos(), p->YPrev());
  458.  
  459.     for(int i = 0; i < DMSelections; i++)
  460.       terminal->Write(displaymenu[i], p->XPos(), p->YOffset(1));
  461.     
  462.     terminal->Write("Press the number of your selection -> ",
  463.             p->XPos(), p->YOffset(2));
  464.     
  465.     c = terminal->GetChar();
  466.     switch(c) {
  467.       case '0': 
  468.     (*DMFunctions[0]) (); // Call the appropriate menu function
  469.     return;
  470.       case '1':
  471.     (*DMFunctions[1]) (); // Call the appropriate menu function
  472.     break;
  473.  
  474.       case '2':
  475.     (*DMFunctions[2]) (); // Call the appropriate menu function
  476.     break;
  477.     
  478.       default:
  479.     break;
  480.     }
  481.   }
  482. }
  483.  
  484. void FileMenu()
  485. {
  486.   int c;
  487.   Coords *p = new Coords(0, 0);
  488.  
  489.   while(1) {
  490.     p->SetXY(0, 0);
  491.     p->SetX(terminal->Center(FOMTitle));
  492.     p->SetY(terminal->ScreenCenter(FOMSelections));
  493.     terminal->ClearScreen();
  494.     terminal->Write(FOMTitle, p->XPos(), p->YPrev());
  495.  
  496.     for(int i = 0; i < FOMSelections; i++)
  497.       terminal->Write(filemenu[i], p->XPos(), p->YOffset(1));
  498.     
  499.     terminal->Write("Press the number of your selection -> ",
  500.             p->XPos(), p->YOffset(2));
  501.     
  502.     c = terminal->GetChar();
  503.     switch(c) {
  504.       case '0': 
  505.     (*FOMFunctions[0]) (); // Call the appropriate menu function
  506.     return;
  507.       case '1':
  508.     (*FOMFunctions[1]) (); // Call the appropriate menu function
  509.     break;
  510.       case '2':
  511.     (*FOMFunctions[2]) (); // Call the appropriate menu function
  512.     break;
  513.       case '3':
  514.     (*FOMFunctions[3]) (); // Call the appropriate menu function
  515.     break;
  516.       case '4':
  517.     (*FOMFunctions[4]) (); // Call the appropriate menu function
  518.     break;
  519.       case '5':
  520.     (*FOMFunctions[5]) (); // Call the appropriate menu function
  521.     break;
  522.       case '6':
  523.     (*FOMFunctions[6]) (); // Call the appropriate menu function
  524.     break;
  525.       case '7':
  526.     (*FOMFunctions[7]) (); // Call the appropriate menu function
  527.     break;
  528.       case '8':
  529.     (*FOMFunctions[8]) (); // Call the appropriate menu function
  530.     break;
  531.       default:
  532.     break;
  533.     }
  534.   }
  535. }
  536.  
  537. void PrintMenu()
  538. {
  539.   int c;
  540.   Coords *p = new Coords(0, 0);
  541.  
  542.   while(1) {
  543.     p->SetXY(0, 0);
  544.     p->SetX(terminal->Center(PMTitle));
  545.     p->SetY(terminal->ScreenCenter(PMSelections));
  546.     terminal->ClearScreen();
  547.     terminal->Write(PMTitle, p->XPos(), p->YPrev());
  548.  
  549.     for(int i = 0; i < PMSelections; i++)
  550.       terminal->Write(printmenu[i], p->XPos(), p->YOffset(1));
  551.     
  552.     terminal->Write("Press the number of your selection -> ",
  553.             p->XPos(), p->YOffset(2));
  554.     
  555.     c = terminal->GetChar();
  556.     switch(c) {
  557.       case '0': 
  558.     (*PMFunctions[0]) (); // Call the appropriate menu function
  559.     return;
  560.       case '1':
  561.     (*PMFunctions[1]) (); // Call the appropriate menu function
  562.     break;
  563.       case '2':
  564.     (*PMFunctions[2]) (); // Call the appropriate menu function
  565.     break;
  566.       case '3':
  567.     (*PMFunctions[3]) (); // Call the appropriate menu function
  568.     break;
  569.       case '4':
  570.     (*PMFunctions[4]) (); // Call the appropriate menu function
  571.     break;
  572.       case '5':
  573.     (*PMFunctions[5]) (); // Call the appropriate menu function
  574.     break;
  575.       default:
  576.     break;
  577.     }
  578.   }
  579. }
  580.  
  581. void Exit()
  582. {
  583.   // Nothing to do
  584. }
  585.  
  586. void Return()
  587. {
  588.   // Nothing to do
  589. }
  590.  
  591. int LoadIndexKeys()
  592. {
  593.   // Clear the doubly linked list
  594.   dllist->Clear();
  595.  
  596.   BtreeWalker btw(DB->Index());
  597.   unsigned num_objects = btw.Sort(LoadKeys);
  598.  
  599.   return num_objects;
  600. }
  601.  
  602. void DisplayAll()
  603. {
  604.   if(DB->RebuildIndex()) {
  605.     terminal->Write("The index file needs to be rebuilt.", 0, 1);
  606.     terminal->AnyKey(0, 2);
  607.     return;
  608.   }
  609.  
  610.   StrDB strdb(DB);
  611.   Coords *p = new Coords(0, 0);
  612.  
  613.   terminal->ClearScreen();      
  614.   LoadIndexKeys();  
  615.  
  616.   dllistptr = dllist->GetFront();
  617.   while(!dllist->IsHeader(dllistptr)) {
  618.     terminal->ClearScreen();      
  619.     p->SetXY(0, 0); // Reset x and y positions
  620.     strdb.ReadObject(dllistptr->Data.object_address);
  621.     DisplayObject(strdb, p);
  622.     terminal->Write("(C)-Change, (D)-Delete, (P)-Print, (X)-Exit",
  623.             p->XPos(), p->YOffset(2));
  624.     terminal->Write(", Any other key to continue");
  625.     int c = terminal->GetChar();
  626.     switch(c) {
  627.       case 'c': case 'C': 
  628.     terminal->ClearScreen();
  629.     p->SetXY(0, 0);
  630.     ChangeObject(strdb, p);
  631.     break;
  632.           
  633.       case 'd': case 'D': {
  634.     int yn = terminal->YesNo("Are you sure you want to delete (y/n)",
  635.                  p->XPos(), p->YOffset(2));
  636.     if(!yn) break;
  637.     strdb.DeleteObject();
  638.     break;
  639.       }
  640.       
  641.       case 'p': case 'P':
  642.     p->YOffset(1);
  643.     PrintObject(strdb, p);
  644.     break;
  645.     
  646.       case 'x': case 'X':
  647.     dllist->Clear();
  648.     delete p;
  649.     return;
  650.           
  651.       default:
  652.     break;
  653.     }
  654.     dllistptr = dllistptr->GetNext(); 
  655.   }
  656.  
  657.   dllist->Clear();
  658.   delete p;
  659. }
  660.  
  661. void ItemBar(Coords *p)
  662. // Displays the Key data member and the data member 2 - 5
  663. {
  664.   int x = p->XPos(); 
  665.   if(KeyName != 0) terminal->Write(KeyName, p->XPos(), p->YPos());
  666.   if(M2Name != 0)
  667.     terminal->Write(M2Name, p->XOffset(StringOffset+1), p->YPos());
  668.   if(M3Name != 0)
  669.     terminal->Write(M3Name, p->XOffset(StringOffset+1), p->YPos());
  670.   if(M4Name != 0)
  671.     terminal->Write(M4Name, p->XOffset(StringOffset+1), p->YPos());
  672.   if(M5Name != 0)
  673.     terminal->Write(M5Name, p->XOffset(StringOffset+1), p->YPos());
  674.   terminal->MoveCursor(0, p->YOffset(1));
  675.   int i = 0;
  676.   while (i++ < terminal->MaxCols()-1) terminal->Write('=');
  677.   p->YOffset(1);
  678.   p->SetX(x);
  679. }
  680.  
  681. void DisplayLBL()
  682. {
  683.   if(DB->RebuildIndex()) {
  684.     terminal->Write("The index file needs to be rebuilt.", 0, 1);
  685.     terminal->AnyKey(0, 2);
  686.     return;
  687.   }
  688.  
  689.   StrDB strdb(DB);
  690.   int c;
  691.   unsigned count = 0;
  692.   Coords *p = new Coords(0, 0);
  693.   terminal->ClearScreen();
  694.  
  695.   ItemBar(p);
  696.  
  697.   LoadIndexKeys();
  698.  
  699.   dllistptr = dllist->GetFront();
  700.   while(!dllist->IsHeader(dllistptr)) {
  701.     // Display the first object
  702.     strdb.ReadObject(dllistptr->Data.object_address);
  703.     LineByLine(strdb, p);
  704.     p->YOffset(1);
  705.     dllistptr = dllistptr->GetNext(); 
  706.     count++;
  707.     if(count > 5) {
  708.       terminal->Write("(X)-Exit", p->XPos(), p->YOffset(2));
  709.       terminal->Write(", Any other key to continue");
  710.       c = terminal->GetChar();
  711.       switch(c) {
  712.     case 'x': case 'X':
  713.       dllist->Clear();
  714.       delete p; // Free Coords pointer
  715.       return;
  716.         
  717.     default:
  718.       break;
  719.       }
  720.       terminal->ClearScreen();
  721.       p->SetXY(0, 0);
  722.       ItemBar(p);
  723.       count = 0;
  724.     }
  725.   }
  726.  
  727.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  728.   dllist->Clear();
  729.   delete p; // Free Coords pointer
  730. }
  731.  
  732. void Remove()
  733. {
  734.   if(KeyName == 0) return;
  735.  
  736.   if(!AdminRights) {
  737.     terminal->ClearScreen();
  738.     terminal->Write("You do not have Admin User Privileges", 0, 1);
  739.     terminal->AnyKey(0, 2);
  740.     return;
  741.   }
  742.   
  743.   terminal->ClearScreen();
  744.   Coords *p = new Coords(0, 0);
  745.   char buf[KeyBuf]; 
  746.  
  747.   terminal->Write(KeyName, p->XPos(), p->YPos());
  748.   terminal->Write(" to delete -> ");
  749.   terminal->GetString(buf);
  750.  
  751.   StrDB strdb(DB);
  752.   strdb.SetKM(buf);
  753.  
  754.   FAU addr = strdb.FindObject();
  755.    
  756.   if(!addr) { 
  757.     terminal->Write("Could not find: ", p->XPos(), p->YOffset(2));
  758.     terminal->Write(buf);
  759.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  760.     delete p; // Free the Coord pointer
  761.     return;
  762.   }
  763.   int yn = terminal->YesNo("Are you sure you want to delete (y/n)",
  764.                p->XPos(), p->YOffset(2));
  765.   if(!yn) {
  766.     delete p; // Free Coord pointer
  767.     return;
  768.   }
  769.   
  770.   strdb.DeleteObject();
  771.   terminal->Write("Deleted entry for: ", p->XPos(), p->YOffset(2));
  772.   terminal->Write(buf);
  773.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  774.   delete p; // Free Coord pointer
  775. }
  776.  
  777. void FileStats()
  778. {
  779.   VBDStats(terminal, DB->OpenDatabase());
  780.   VBDStats(terminal, DB->OpenIndexFile());
  781. }
  782.  
  783. void PrintItemBar(ofstream &stream, int abv)
  784. {
  785.  
  786.   int i = 0;
  787.   if(KeyName != 0) ASPrint(KeyName, stream, StringOffset+1);
  788.   if(M2Name != 0) ASPrint(M2Name, stream, StringOffset+1);
  789.   if(M3Name != 0) ASPrint(M3Name, stream, StringOffset+1);
  790.   if(M4Name != 0) ASPrint(M4Name, stream, StringOffset+1);
  791.   if(abv) { // Print abbreviated list for portrait print outs
  792.     if(M5Name != 0) ASPrint(M5Name, stream, StringOffset);
  793.     stream << asLineFeed;
  794.     i = 0;
  795.     while (i++ < asPrintCols-1) stream << '=';
  796.     stream << asLineFeed;
  797.     return;
  798.   }
  799.   else { // Print full listing for landscape print outs
  800.     if(M5Name != 0) ASPrint(M5Name, stream, StringOffset+1);
  801.     if(M6Name != 0) ASPrint(M6Name, stream, StringOffset+1);
  802.     if(M7Name != 0) ASPrint(M7Name, stream, StringOffset+1);
  803.     if(M8Name != 0) ASPrint(M8Name, stream, StringOffset);
  804.     stream << asLineFeed;
  805.     i = 0;
  806.     while (i++ < asPrintColsLong-1) stream << '=';
  807.     stream << asLineFeed;
  808.   }
  809. }
  810.  
  811. void PrintLineByLine(StrDB &strdb, ofstream &stream, int abv)
  812. {
  813.   int i = 0;
  814.   
  815.   if(KeyName != 0) ASPrint(strdb.GetKM(), stream, StringOffset+1);
  816.   if(M2Name != 0) ASPrint(strdb.GetM2(), stream, StringOffset+1);
  817.   if(M3Name != 0) ASPrint(strdb.GetM3(), stream, StringOffset+1);
  818.   if(M4Name != 0) ASPrint(strdb.GetM4(), stream, StringOffset+1);
  819.   if(abv) { // Print abbreviated list for portrait print outs
  820.     if(M5Name != 0) ASPrint(strdb.GetM5(), stream, StringOffset);
  821.     stream << asLineFeed;
  822.     i = 0;
  823.     while (i++ < asPrintCols-1) stream << '-';
  824.     stream << asLineFeed;
  825.     return;
  826.   }
  827.   else { // Print full listing for landscape print outs
  828.     if(M5Name != 0) ASPrint(strdb.GetM5(), stream, StringOffset+1);
  829.     if(M6Name != 0) ASPrint(strdb.GetM6(), stream, StringOffset+1);
  830.     if(M7Name != 0) ASPrint(strdb.GetM7(), stream, StringOffset+1);
  831.     if(M8Name != 0) ASPrint(strdb.GetM8(), stream, StringOffset);
  832.     stream << asLineFeed;
  833.     i = 0;
  834.     while (i++ < asPrintColsLong-1) stream << '-';
  835.     stream << asLineFeed;
  836.   }
  837. }
  838.  
  839. void ASCIIPrintAll()
  840. {
  841.   ASCIIPrint(PORTRAIT);
  842. }
  843.  
  844. void ASCIIPrintAllLong()
  845. {
  846.   ASCIIPrint(LANDSCAPE);
  847. }
  848.  
  849. int ASCIIPrint(PrintMode mode)
  850. {
  851.   char buf[CBuf];
  852.   char *FileName;
  853.   terminal->ClearScreen();
  854.   Coords *p = new Coords(0, 0);
  855.  
  856.   terminal->Write("Enter file name to print to: ",
  857.           p->XPos(), p->YPos());
  858.   terminal->GetString(buf);
  859.  
  860.   char *tmp = new char[strlen(buf)+1];
  861.   tmp[strlen(buf)] = '\0';
  862.   strcpy(tmp, buf);
  863.   
  864.   if(VBDFile::Exists(tmp)) {
  865.     terminal->Write("File: ",
  866.             p->XPos(), p->YOffset(2));
  867.     terminal->Write(tmp);
  868.     terminal->Write(" already exists.");
  869.     int yn = terminal->YesNo("Overwrite it (y/n)?", p->XPos(), p->YOffset(2));
  870.     if(!yn) {
  871.       delete p;
  872.       delete[] tmp;
  873.       return 0;
  874.     }
  875.   }
  876.  
  877.   FileName = tmp;
  878.   delete[] tmp;
  879.   
  880.   ofstream stream(FileName, ios::out); // Open file and truncate it
  881.   terminal->Write("Printing to: ",
  882.           p->XPos(), p->YOffset(2));
  883.   terminal->Write(FileName);
  884.   
  885.   if(!stream) { // Could not open the stream
  886.     terminal->Write("Could not write to: ",
  887.             p->XPos(), p->YOffset(2));
  888.     terminal->Write(FileName);
  889.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  890.     delete p; // Free the Coords pointer
  891.     return 0; 
  892.   }
  893.  
  894.   terminal->Write("Printing...", p->XPos(), p->YOffset(2));
  895.           
  896.   StrDB strdb(DB);
  897.   unsigned count = 0;
  898.  
  899.   if(mode == LANDSCAPE)
  900.     PrintItemBar(stream, 0);
  901.   else
  902.     PrintItemBar(stream);
  903.  
  904.   if(DB->RebuildIndex()) {
  905.     terminal->Write("The index file needs to be rebuilt.",
  906.             p->XPos(), p->YOffset(2));
  907.     terminal->Write(FileName);
  908.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  909.     return 0;
  910.   }
  911.  
  912.   LoadIndexKeys();
  913.  
  914.   dllistptr = dllist->GetFront();
  915.   while(!dllist->IsHeader(dllistptr)) {
  916.     strdb.ReadObject(dllistptr->Data.object_address);
  917.     switch(mode) {
  918.       case PORTRAIT: 
  919.     PrintLineByLine(strdb, stream);
  920.     break;
  921.       case LANDSCAPE: 
  922.     PrintLineByLine(strdb, stream, 0);          
  923.     break;
  924.       default:
  925.         delete p; // Free the Coords pointer
  926.     return 0;
  927.     }
  928.     count++; 
  929.     dllistptr = dllistptr->GetNext(); 
  930.   }
  931.  
  932.   dllist->Clear(); 
  933.   terminal->Write("Finished", p->XPos(), p->YOffset(2));
  934.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  935.   delete p;          // Free the Coords pointer
  936.   stream.close();
  937.   return count;
  938. }
  939.  
  940. void ASCIIPrintObject()
  941. {
  942.   if(KeyName == 0) return;
  943.   
  944.   Coords *p = new Coords(0, 0);
  945.   char buf[KeyBuf];
  946.   
  947.   terminal->ClearScreen();
  948.   terminal->Write(KeyName, p->XPos(), p->YPos());
  949.   terminal->Write(" to print -> ");
  950.   terminal->GetString(buf);
  951.  
  952.   StrDB strdb(DB);
  953.   strdb.SetKM(buf);
  954.  
  955.   FAU addr = strdb.FindObject();
  956.    
  957.   if(!addr) { 
  958.     terminal->Write("Could not find: ", p->XPos(), p->YOffset(2));
  959.     terminal->Write(buf);
  960.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  961.     delete p; // Free Coords pointer
  962.     return;
  963.   }
  964.  
  965.   PrintObject(strdb, p);
  966.   delete p; // Free Coords pointer
  967. }
  968.  
  969. void PrintObject(StrDB &strdb, Coords *p)
  970. {
  971.   char buf[CBuf];
  972.   char *FileName;
  973.   const char *separator = " = ";
  974.   const char *cseparator = ": ";
  975.   
  976.   terminal->Write("Enter file name to print to: ",
  977.           p->XPos(), p->YOffset(1));
  978.   terminal->GetString(buf);
  979.  
  980.   char *tmp = new char[strlen(buf)+1];
  981.   tmp[strlen(buf)] = '\0';
  982.   strcpy(tmp, buf);
  983.   
  984.   if(VBDFile::Exists(tmp)) {
  985.     terminal->Write("File: ",
  986.             p->XPos(), p->YOffset(1));
  987.     terminal->Write(tmp);
  988.     terminal->Write(" already exists.");
  989.     int yn = terminal->YesNo("Overwrite it (y/n)?", p->XPos(), p->YOffset(1));
  990.     if(!yn) {
  991.       delete[] tmp;
  992.       return;
  993.     }
  994.   }
  995.  
  996.   FileName = tmp;
  997.   delete[] tmp;
  998.   
  999.   ofstream stream(FileName, ios::out); // Open file and truncate it
  1000.   terminal->Write("Printing to: ",
  1001.           p->XPos(), p->YOffset(1));
  1002.   terminal->Write(FileName);
  1003.   
  1004.   if(!stream) { // Could not open the stream
  1005.     terminal->Write("Could not write to: ",
  1006.             p->XPos(), p->YOffset(1));
  1007.     terminal->Write(FileName);
  1008.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  1009.     return;
  1010.   }
  1011.  
  1012.   if(KeyName != 0) {
  1013.     ASPrint(KeyName, stream, strlen(KeyName));
  1014.     ASPrint(separator, stream, strlen(separator));
  1015.     ASPrint(strdb.GetKM(), stream, strlen(strdb.GetKM()));
  1016.     stream << asLineFeed;
  1017.   }
  1018.   if(M2Name != 0) {
  1019.     ASPrint(M2Name, stream, strlen(M2Name));
  1020.     ASPrint(separator, stream, strlen(separator));
  1021.     ASPrint(strdb.GetM2(), stream, strlen(strdb.GetM2()));
  1022.     stream << asLineFeed;
  1023.   }
  1024.   if(M3Name != 0) {
  1025.     ASPrint(M3Name, stream, strlen(M3Name));
  1026.     ASPrint(separator, stream, strlen(separator));
  1027.     ASPrint(strdb.GetM3(), stream, strlen(strdb.GetM3()));
  1028.     stream << asLineFeed;
  1029.   }
  1030.   if(M4Name != 0) {
  1031.     ASPrint(M4Name, stream, strlen(M4Name));
  1032.     ASPrint(separator, stream, strlen(separator));
  1033.     ASPrint(strdb.GetM4(), stream, strlen(strdb.GetM4()));
  1034.     stream << asLineFeed;
  1035.   }
  1036.   if(M5Name != 0) {
  1037.     ASPrint(M5Name, stream, strlen(M5Name));
  1038.     ASPrint(separator, stream, strlen(separator));
  1039.     ASPrint(strdb.GetM5(), stream, strlen(strdb.GetM5()));
  1040.     stream << asLineFeed;
  1041.   }
  1042.   if(M6Name != 0) {
  1043.     ASPrint(M6Name, stream, strlen(M6Name));
  1044.     ASPrint(separator, stream, strlen(separator));
  1045.     ASPrint(strdb.GetM6(), stream, strlen(strdb.GetM6()));
  1046.     stream << asLineFeed;
  1047.   }
  1048.   if(M7Name != 0) {
  1049.     ASPrint(M7Name, stream, strlen(M7Name));
  1050.     ASPrint(separator, stream, strlen(separator));
  1051.     ASPrint(strdb.GetM7(), stream, strlen(strdb.GetM7()));
  1052.     stream << asLineFeed;
  1053.   }
  1054.   if(M8Name != 0) {
  1055.     ASPrint(M8Name, stream, strlen(M8Name));
  1056.     ASPrint(separator, stream, strlen(separator));
  1057.     ASPrint(strdb.GetM8(), stream, strlen(strdb.GetM8()));
  1058.     stream << asLineFeed;
  1059.   }
  1060.   if(Comments != 0) {
  1061.     ASPrint(Comments, stream, strlen(Comments));
  1062.     ASPrint(cseparator, stream, strlen(cseparator));
  1063.     ASPrint(strdb.GetCM(), stream, strlen(strdb.GetCM()));
  1064.     stream << asLineFeed;
  1065.   }
  1066.   terminal->Write("Finished", p->XPos(), p->YOffset(1));
  1067.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  1068.   stream.close();
  1069. }
  1070.  
  1071. void Add()
  1072. {
  1073.   if(KeyName == 0) return;
  1074.  
  1075.   if(!AdminRights) {
  1076.     terminal->ClearScreen();
  1077.     terminal->Write("You do not have Admin User Privileges", 0, 1);
  1078.     terminal->AnyKey(0, 2);
  1079.     return;
  1080.   }
  1081.  
  1082.   int r = retrys;
  1083.   
  1084.   Coords *p = new Coords(0, 0);
  1085.   char buf[KeyBuf];
  1086.   terminal->ClearScreen();
  1087.  
  1088.   while(1) {
  1089.     terminal->Write(KeyName, p->XPos(), p->YPos());
  1090.     terminal->Write(" to add -> ");
  1091.     terminal->GetString(buf);
  1092.     if(!*buf) r--; else break;
  1093.     if(!r) {
  1094.       delete p;
  1095.       return;
  1096.     }
  1097.   }
  1098.   
  1099.   StrDB strdb(DB);
  1100.   UString key_buf(buf);
  1101.  
  1102.   // Remove any leading space from the key name entry
  1103.   int offset = key_buf.Find(" ");
  1104.   if(offset == 0) key_buf.DeleteAt(offset, 1);
  1105.     
  1106.   if(key_buf == "") { // Check for a key name valid input
  1107.     delete p;
  1108.     return;
  1109.   }
  1110.  
  1111.   strdb.SetKM(key_buf);
  1112.  
  1113.   FAU addr = strdb.FindObject();
  1114.    
  1115.   if(addr) { 
  1116.     terminal->Write(buf, p->XPos(), p->YOffset(2));
  1117.     terminal->Write(" entry already exists."); 
  1118.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  1119.     delete p; // Free Coords pointer
  1120.     return;
  1121.   }
  1122.  
  1123.   AddObject(strdb, p);
  1124.   delete p; // Free Coords pointer
  1125. }
  1126.  
  1127. void AddObject(StrDB &strdb, Coords *p)
  1128. {
  1129.   char buf[KeyBuf];
  1130.   char cbuf[CBuf];
  1131.  
  1132.   if(M2Name != 0) {
  1133.   terminal->Write(M2Name, p->XPos(), p->YOffset(2));
  1134.   terminal->Write(" -> ");
  1135.   terminal->GetString(buf);
  1136.   strdb.SetM2(buf);
  1137.   }
  1138.   if(M3Name != 0) {
  1139.   terminal->Write(M3Name, p->XPos(), p->YOffset(1));
  1140.   terminal->Write(" -> ");
  1141.   terminal->GetString(buf);
  1142.   strdb.SetM3(buf);
  1143.   }
  1144.   if(M4Name != 0) {
  1145.   terminal->Write(M4Name, p->XPos(), p->YOffset(1));
  1146.   terminal->Write(" -> ");
  1147.   terminal->GetString(buf);
  1148.   strdb.SetM4(buf);
  1149.   }
  1150.   if(M5Name != 0) {
  1151.     terminal->Write(M5Name, p->XPos(), p->YOffset(1));
  1152.     terminal->Write(" -> ");
  1153.     terminal->GetString(buf);
  1154.     strdb.SetM5(buf);
  1155.   }
  1156.   if(M6Name != 0) {
  1157.     terminal->Write(M6Name, p->XPos(), p->YOffset(1));
  1158.     terminal->Write(" -> ");
  1159.     terminal->GetString(buf);
  1160.     strdb.SetM6(buf);
  1161.   }
  1162.   if(M7Name != 0) {
  1163.     terminal->Write(M7Name, p->XPos(), p->YOffset(1));
  1164.     terminal->Write(" -> ");
  1165.     terminal->GetString(buf);
  1166.     strdb.SetM7(buf);
  1167.   }
  1168.   if(M8Name != 0) {
  1169.     terminal->Write(M8Name, p->XPos(), p->YOffset(1));
  1170.     terminal->Write(" -> ");
  1171.     terminal->GetString(buf);
  1172.     strdb.SetM8(buf);
  1173.   }
  1174.   if(Comments != 0) {
  1175.     terminal->Write(Comments, p->XPos(), p->YOffset(1));
  1176.     terminal->Write(" -> ");
  1177.     terminal->GetString(cbuf);
  1178.     strdb.SetCM(cbuf);
  1179.   }
  1180.   terminal->Write("(A)-Abort (C)-Change, Any other key to accept entry",
  1181.           p->XPos(), p->YOffset(2));
  1182.   int c = terminal->GetChar();
  1183.   switch(c) {
  1184.     case 'c': case 'C':
  1185.       terminal->ClearScreen();
  1186.       p->SetXY(0, 0);
  1187.       ChangeObject(strdb, p, 1); 
  1188.       break;
  1189.     case 'a': case 'A':
  1190.       return;
  1191.     default:
  1192.       break;
  1193.   }
  1194.  
  1195.   FAU addr = strdb.AddObject(0); // Write the object to the file
  1196.   if(!addr) {
  1197.     terminal->Write("Could not add item to database",
  1198.                     p->XPos(), p->YOffset(2));
  1199.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  1200.     return;
  1201.   }
  1202.   
  1203.   terminal->Write("Item was added to the database",
  1204.                   p->XPos(), p->YOffset(2));
  1205.  
  1206.   terminal->Write("Add another (y/n)", p->XPos(), p->YOffset(2));
  1207.   if(terminal->GetYesNo()) Add(); else return; 
  1208. }
  1209.  
  1210. void FindBy(const char *MemberName, StrDBItem item)
  1211. {  
  1212.   if(MemberName == 0) return;
  1213.  
  1214.   terminal->ClearScreen();
  1215.   Coords *p = new Coords(0, 0);
  1216.   char buf[KeyBuf];
  1217.   unsigned offset = 0;
  1218.   
  1219.   StrDB strdb(DB);
  1220.  
  1221.   terminal->Write("Enter complete string or use ", p->XPos(), p->YPos());
  1222.   terminal->Write(WildCard);
  1223.   terminal->Write(" for a wild card.");
  1224.   terminal->Write(MemberName, p->XPos(), p->YOffset(2));
  1225.   terminal->Write(" -> ");
  1226.   terminal->GetString(buf);
  1227.   UString str(buf);
  1228.   offset = str.Find(WildCard, offset); // Look for wild card character
  1229.  
  1230.   if(DB->RebuildIndex()) {
  1231.     terminal->Write("The index file needs to be rebuilt.",
  1232.             p->XPos(), p->YOffset(2));
  1233.     terminal->AnyKey(p->XPos(), p->YOffset(1));
  1234.     delete p;
  1235.     return;
  1236.   }
  1237.   
  1238.   if(offset == UString::NoMatch) { // No wild cards found
  1239.     strdb.SetKM(buf);
  1240.     StrDBSearch(strdb, item, str, p);
  1241.     delete p; // Free the Coord pointer
  1242.     return;
  1243.   }
  1244.  
  1245.   StrDBSearch(strdb, item, str, p, WildCard);
  1246.   delete p; // Free the Coord pointer
  1247. }
  1248.  
  1249. void FindByKeyName()
  1250. {
  1251.   FindBy(KeyName, KEYMEMBER);
  1252. }
  1253.  
  1254. void FindByM2Name()
  1255. {
  1256.   FindBy(M2Name, M2NAME);
  1257. }
  1258.  
  1259. void FindByM3Name()
  1260. {
  1261.   FindBy(M3Name, M3NAME);
  1262. }
  1263.  
  1264. void FindByM4Name()
  1265. {
  1266.   FindBy(M4Name, M4NAME);
  1267. }
  1268.  
  1269. void FindByM5Name()
  1270. {
  1271.   FindBy(M5Name, M5NAME);
  1272. }
  1273.  
  1274. void FindByM6Name()
  1275. {
  1276.   FindBy(M6Name, M6NAME);
  1277. }
  1278.  
  1279. void FindByM7Name()
  1280. {
  1281.   FindBy(M7Name, M7NAME);
  1282. }
  1283.  
  1284. void FindByM8Name()
  1285. {
  1286.   FindBy(M8Name, M8NAME);
  1287. }
  1288.  
  1289. void FindByComments()
  1290. {
  1291.   FindBy(Comments, COMMENTS);
  1292. }
  1293.  
  1294. void Change()
  1295. {
  1296.   if(KeyName == 0) return;
  1297.  
  1298.   if(!AdminRights) {
  1299.     terminal->ClearScreen();
  1300.     terminal->Write("You do not have Admin User Privileges", 0, 1);
  1301.     terminal->AnyKey(0, 2);
  1302.     return;
  1303.   }
  1304.  
  1305.   Coords *p = new Coords(0, 0);
  1306.   char buf[KeyBuf];
  1307.   
  1308.   terminal->ClearScreen();
  1309.   terminal->Write(KeyName, p->XPos(), p->YPos());
  1310.   terminal->Write(" to change -> ");
  1311.   terminal->GetString(buf);
  1312.  
  1313.   StrDB strdb(DB);
  1314.   strdb.SetKM(buf);
  1315.  
  1316.   FAU addr = strdb.FindObject();
  1317.    
  1318.   if(!addr) { 
  1319.     terminal->Write("Could not find: ", p->XPos(), p->YOffset(2));
  1320.     terminal->Write(buf);
  1321.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  1322.     delete p; // Free Coords pointer
  1323.     return;
  1324.   }
  1325.  
  1326.   ChangeObject(strdb, p);
  1327.   delete p; // Free Coords pointer
  1328. }
  1329.  
  1330. void ChangeObject(StrDB &strdb, Coords *p, int adding)
  1331. {
  1332.   char buf[KeyBuf];
  1333.   char cbuf[CBuf];
  1334.   
  1335.   // Buffer the object's data to allow changes to be canceled
  1336.   StrDB ob;
  1337.   ob.Copy(strdb);
  1338.   FAU addr;
  1339.   StrDB changed(DB); // Temp buffer used to record changes
  1340.   
  1341.   char *prompt = "Press the number/letter of your selection -> ";  
  1342.   int c, x, y, x_prev, y_prev, x_prompt, y_prompt;
  1343.   x_prev = p->XPos(); y_prev = p->YPos();
  1344.  
  1345.   while(1) {
  1346.     p->SetXY(x_prev, y_prev);
  1347.     terminal->Write("(C) Cancel change", p->XPos(), p->YOffset(2));
  1348.     if(adding) {
  1349.       if(KeyName != 0) {
  1350.     terminal->Write("(0) ", p->XPos(), p->YOffset(1));
  1351.     terminal->Write(KeyName); terminal->Write(" = ");
  1352.     terminal->Write(strdb.GetKM());
  1353.     terminal->ClearLine();
  1354.       }
  1355.     }
  1356.     else {
  1357.       if(KeyName != 0) {
  1358.     terminal->Write("(-) ", p->XPos(), p->YOffset(1));
  1359.     terminal->Write(KeyName); terminal->Write(" = ");
  1360.     terminal->Write(strdb.GetKM());
  1361.     terminal->ClearLine();
  1362.       }
  1363.     }
  1364.     if(M2Name != 0) {
  1365.       terminal->Write("(1) ", p->XPos(), p->YOffset(1));
  1366.       terminal->Write(M2Name); terminal->Write(" = ");
  1367.       terminal->Write(strdb.GetM2());
  1368.       terminal->ClearLine();
  1369.     }
  1370.     if(M3Name != 0) {
  1371.       terminal->Write("(2) ", p->XPos(), p->YOffset(1));
  1372.       terminal->Write(M3Name); terminal->Write(" = ");
  1373.       terminal->Write(strdb.GetM3());
  1374.       terminal->ClearLine();
  1375.     }
  1376.     if(M4Name != 0) {
  1377.       terminal->Write("(3) ", p->XPos(), p->YOffset(1));
  1378.       terminal->Write(M4Name); terminal->Write(" = ");
  1379.       terminal->Write(strdb.GetM4());
  1380.       terminal->ClearLine();
  1381.     }
  1382.     if(M5Name != 0) {
  1383.       terminal->Write("(4) ", p->XPos(), p->YOffset(1));
  1384.       terminal->Write(M5Name); terminal->Write(" = ");
  1385.       terminal->Write(strdb.GetM5());
  1386.       terminal->ClearLine();
  1387.     }
  1388.     if(M6Name != 0) {
  1389.       terminal->Write("(5) ", p->XPos(), p->YOffset(1));
  1390.       terminal->Write(M6Name); terminal->Write(" = ");
  1391.       terminal->Write(strdb.GetM6());
  1392.       terminal->ClearLine();
  1393.     }
  1394.     if(M7Name != 0) {
  1395.       terminal->Write("(6) ", p->XPos(), p->YOffset(1));
  1396.       terminal->Write(M7Name); terminal->Write(" = ");
  1397.       terminal->Write(strdb.GetM7());
  1398.       terminal->ClearLine();
  1399.     }
  1400.     if(M8Name != 0) {
  1401.       terminal->Write("(7) ", p->XPos(), p->YOffset(1));
  1402.       terminal->Write(M8Name); terminal->Write(" = ");
  1403.       terminal->Write(strdb.GetM8());
  1404.       terminal->ClearLine();
  1405.     }
  1406.     if(Comments != 0) {
  1407.       terminal->Write("(8) ", p->XPos(), p->YOffset(1));
  1408.       terminal->Write(Comments); terminal->Write(" = ");
  1409.       terminal->Write(strdb.GetCM());
  1410.       terminal->ClearLine();
  1411.     }
  1412.     terminal->Write("(A) Accept changes", p->XPos(), p->YOffset(1));
  1413.     
  1414.     terminal->Write(prompt, p->XPos(), p->YOffset(2));
  1415.     x_prompt = p->XPos() + strlen(prompt);
  1416.     y_prompt = p->YPos();
  1417.   
  1418.     x = p->XPos();
  1419.     y = p->YPos() + 2;
  1420.  
  1421.     c = terminal->GetChar();
  1422.     switch(c) {
  1423.       case 'C': case 'c': 
  1424.         strdb.Copy(ob);
  1425.     return;
  1426.  
  1427.       case '0':
  1428.     // User not allowed to change name unless adding a new object
  1429.     if(!adding) break; 
  1430.     if(KeyName != 0) { 
  1431.       terminal->Write(KeyName, x, y);
  1432.       terminal->Write(" -> ");
  1433.       terminal->GetString(buf);
  1434.       strdb.SetKM(buf);
  1435.       addr = strdb.FindObject();
  1436.          if(addr) { 
  1437.         terminal->Write("Entry already exists!", x, y+1);
  1438.         terminal->AnyKey();
  1439.         terminal->ClearLine(x, y+1);
  1440.         terminal->ClearLine(x, y);
  1441.         terminal->MoveCursor(x_prev, y_prev);
  1442.         break;
  1443.       }
  1444.       strdb.SetKM(buf);
  1445.       terminal->ClearLine(x, y);
  1446.       terminal->MoveCursor(x_prev, y_prev);
  1447.     }
  1448.     break;
  1449.  
  1450.       case '1':
  1451.     if(M2Name != 0) { 
  1452.       terminal->Write(M2Name, x, y);
  1453.       terminal->Write(" -> ");
  1454.       terminal->GetString(buf);
  1455.       strdb.SetM2(buf);
  1456.       terminal->ClearLine(x, y);
  1457.       terminal->MoveCursor(x_prev, y_prev);
  1458.     }
  1459.     break;
  1460.  
  1461.       case '2':
  1462.     if(M3Name != 0) { 
  1463.       terminal->Write(M3Name, x, y);
  1464.       terminal->Write(" -> ");
  1465.       terminal->GetString(buf);
  1466.       strdb.SetM3(buf);
  1467.       terminal->ClearLine(x, y);
  1468.       terminal->MoveCursor(x_prev, y_prev);
  1469.     }
  1470.     break;
  1471.     
  1472.       case '3':
  1473.     if(M4Name != 0) { 
  1474.       terminal->Write(M4Name, x, y);
  1475.       terminal->Write(" -> ");
  1476.       terminal->GetString(buf);
  1477.       strdb.SetM4(buf);
  1478.       terminal->ClearLine(x, y);
  1479.       terminal->MoveCursor(x_prev, y_prev);
  1480.     }
  1481.     break;
  1482.  
  1483.       case '4':
  1484.     if(M5Name != 0) { 
  1485.       terminal->Write(M5Name, x, y);
  1486.       terminal->Write(" -> ");
  1487.       terminal->GetString(buf);
  1488.       strdb.SetM5(buf);
  1489.       terminal->ClearLine(x, y);
  1490.       terminal->MoveCursor(x_prev, y_prev);
  1491.     }
  1492.     break;
  1493.  
  1494.       case '5':
  1495.     if(M6Name != 0) { 
  1496.       terminal->Write(M6Name, x, y);
  1497.       terminal->Write(" -> ");
  1498.       terminal->GetString(buf);
  1499.       strdb.SetM6(buf);
  1500.       terminal->ClearLine(x, y);
  1501.       terminal->MoveCursor(x_prev, y_prev);
  1502.     }
  1503.     break;
  1504.  
  1505.       case '6':
  1506.     if(M7Name != 0) { 
  1507.       terminal->Write(M7Name, x, y);
  1508.       terminal->Write(" -> ");
  1509.       terminal->GetString(buf);
  1510.       strdb.SetM7(buf);
  1511.       terminal->ClearLine(x, y);
  1512.       terminal->MoveCursor(x_prev, y_prev);
  1513.     }
  1514.     break;
  1515.  
  1516.       case '7':
  1517.     if(M8Name != 0) { 
  1518.       terminal->Write(M8Name, x, y);
  1519.       terminal->Write(" -> ");
  1520.       terminal->GetString(buf);
  1521.       strdb.SetM8(buf);
  1522.       terminal->ClearLine(x, y);
  1523.       terminal->MoveCursor(x_prev, y_prev);
  1524.     }
  1525.     break;
  1526.  
  1527.       case '8':
  1528.     if(Comments != 0) { 
  1529.       terminal->Write(Comments, x, y);
  1530.       terminal->Write(" -> ");
  1531.       terminal->GetString(cbuf);
  1532.       strdb.SetCM(cbuf);
  1533.       terminal->ClearLine(x, y);
  1534.       terminal->MoveCursor(x_prev, y_prev);
  1535.     }
  1536.     break;
  1537.     
  1538.       case 'A': case 'a':
  1539.     if(adding) return; // New object, no need to reallocate space
  1540.         if(strdb.FullCompare(ob)) return; // The object has not changed
  1541.         changed.Copy(strdb);  // Make a copy of the changes
  1542.  
  1543.     // Remove the original object 
  1544.         strdb.DeleteObject(); 
  1545.     changed.AddObject(0); // Add the changed object back to the database
  1546.     return;
  1547.     
  1548.       default:
  1549.     break;
  1550.     }
  1551.   }
  1552. }
  1553.  
  1554. void DisplayObject(StrDB &strdb, Coords *p)
  1555. // Display's the complete object with all details.
  1556. {
  1557.   if(KeyName != 0) {
  1558.     terminal->Write(KeyName, p->XPos(), p->YPos());
  1559.     terminal->Write(" = ");
  1560.     terminal->Write(strdb.GetKM());
  1561.   }
  1562.   if(M2Name != 0) {
  1563.     terminal->Write(M2Name, p->XPos(), p->YOffset(1));
  1564.     terminal->Write(" = ");
  1565.     terminal->Write(strdb.GetM2());
  1566.   }
  1567.   if(M3Name != 0) {
  1568.     terminal->Write(M3Name, p->XPos(), p->YOffset(1));
  1569.     terminal->Write(" = ");
  1570.     terminal->Write(strdb.GetM3());
  1571.   }
  1572.   if(M4Name != 0) {
  1573.     terminal->Write(M4Name, p->XPos(), p->YOffset(1));
  1574.     terminal->Write(" = ");
  1575.     terminal->Write(strdb.GetM4());
  1576.   }
  1577.   if(M5Name != 0) { 
  1578.     terminal->Write(M5Name, p->XPos(), p->YOffset(1));
  1579.     terminal->Write(" = ");
  1580.     terminal->Write(strdb.GetM5());
  1581.   }
  1582.   if(M6Name != 0) {
  1583.     terminal->Write(M6Name, p->XPos(), p->YOffset(1));
  1584.     terminal->Write(" = ");
  1585.     terminal->Write(strdb.GetM6());
  1586.   }
  1587.   if(M7Name != 0) {
  1588.     terminal->Write(M7Name, p->XPos(), p->YOffset(1));
  1589.     terminal->Write(" = ");
  1590.     terminal->Write(strdb.GetM7());
  1591.   }
  1592.   if(M8Name != 0) {
  1593.     terminal->Write(M8Name, p->XPos(), p->YOffset(1));
  1594.     terminal->Write(" = ");
  1595.     terminal->Write(strdb.GetM8());
  1596.   }
  1597.   if(Comments != 0) {
  1598.     terminal->Write(Comments, p->XPos(), p->YOffset(1));
  1599.     terminal->Write(": ");
  1600.     terminal->Write(strdb.GetCM());
  1601.   }
  1602. }
  1603.  
  1604. void DisplayString(const char *s)
  1605. {
  1606.   int len = strlen(s);
  1607.   int offset = StringOffset;
  1608.   char *buf = new char[len + 1];
  1609.   buf[len] = '\0';
  1610.   strcpy(buf, s);
  1611.   if(len < StringOffset) offset = len;
  1612.   for(int i = 0; i < offset; i++)
  1613.     terminal->Write(buf[i]);
  1614.   delete[] buf;
  1615. }
  1616.  
  1617. void LineByLine(StrDB &strdb, Coords *p)
  1618. // Display objects line by line with partial details
  1619. {
  1620.   int x = p->XPos();
  1621.  
  1622.   if(KeyName != 0) {
  1623.     terminal->MoveCursor(p->XPos(), p->YPos());
  1624.     DisplayString(strdb.GetKM());
  1625.   }
  1626.  
  1627.   if(M2Name != 0) {
  1628.     terminal->MoveCursor(p->XOffset(StringOffset+1), p->YPos()); 
  1629.     DisplayString(strdb.GetM2());
  1630.   }
  1631.   if(M3Name != 0) {
  1632.     terminal->MoveCursor(p->XOffset(StringOffset+1), p->YPos());
  1633.     DisplayString(strdb.GetM3());
  1634.   }
  1635.   if(M4Name != 0) {
  1636.     terminal->MoveCursor(p->XOffset(StringOffset+1), p->YPos());
  1637.     DisplayString(strdb.GetM4());
  1638.   }
  1639.   if(M5Name != 0) {
  1640.     terminal->MoveCursor(p->XOffset(StringOffset+1), p->YPos());
  1641.     DisplayString(strdb.GetM5());
  1642.   }
  1643.  
  1644.   int i = 0;
  1645.   terminal->MoveCursor(0, p->YOffset(1));
  1646.   while (i++ < terminal->MaxCols()-1) terminal->Write('-');
  1647.   p->SetX(x);
  1648. }
  1649.  
  1650. void Version()
  1651. {
  1652.   printf("\n%s program version %.3f\n", ProgramName, VersionNumber);
  1653.   exit(0);
  1654. }
  1655.  
  1656. void ExportToASCII()
  1657. {
  1658.   char buf[CBuf];
  1659.   char *FileName;
  1660.   const char dchar = '\t';   // Text delimiter
  1661.   const char filter = '\t';    // Filter tabs
  1662.   const char *Fill = "None"; // Fill character string
  1663.  
  1664.   terminal->ClearScreen();
  1665.  
  1666.   if(DB->RebuildIndex()) {
  1667.     terminal->Write("The index file needs to be rebuilt.", 0, 1);
  1668.     terminal->AnyKey(0, 2);
  1669.     return;
  1670.   }
  1671.  
  1672.   Coords *p = new Coords(0, 0);
  1673.  
  1674.   terminal->Write("Export database to ASCII file delimited by tabs",
  1675.           p->XPos(), p->YPos());
  1676.  
  1677.   terminal->Write("Enter file name to export to: ",
  1678.           p->XPos(), p->YOffset(2));
  1679.   terminal->GetString(buf);
  1680.  
  1681.   char *tmp = new char[strlen(buf)+1];
  1682.   tmp[strlen(buf)] = '\0';
  1683.   strcpy(tmp, buf);
  1684.   
  1685.   if(VBDFile::Exists(tmp)) {
  1686.     terminal->Write("File: ",
  1687.             p->XPos(), p->YOffset(2));
  1688.     terminal->Write(tmp);
  1689.     terminal->Write(" already exists.");
  1690.     int yn = terminal->YesNo("Overwrite it (y/n)?", p->XPos(), p->YOffset(2));
  1691.     if(!yn) {
  1692.       delete p;
  1693.       delete[] tmp;
  1694.       return;
  1695.     }
  1696.   }
  1697.  
  1698.   FileName = tmp;
  1699.   delete[] tmp;
  1700.   ofstream stream(FileName, ios::out); // Open file and truncate it
  1701.   terminal->Write("Exporting database to: ",
  1702.           p->XPos(), p->YOffset(2));
  1703.   terminal->Write(FileName);
  1704.   
  1705.   if(!stream) { // Could not open the stream
  1706.     terminal->Write("Could not write to: ",
  1707.             p->XPos(), p->YOffset(2));
  1708.     terminal->Write(FileName);
  1709.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  1710.     delete p; // Free the Coords pointer
  1711.     return; 
  1712.   }
  1713.  
  1714.   StrDB strdb(DB);
  1715.  
  1716.   // Write the item bar to the file first
  1717.   if(KeyName != 0) {
  1718.     ASPrint(KeyName, stream, strlen(KeyName));
  1719.     stream << dchar;
  1720.   }
  1721.   if(M2Name != 0) {
  1722.     ASPrint(M2Name, stream, strlen(M2Name));
  1723.     stream << dchar;
  1724.   }
  1725.   if(M3Name != 0) {
  1726.     ASPrint(M3Name, stream, strlen(M3Name));
  1727.     stream << dchar;
  1728.   }
  1729.   if(M4Name != 0) {
  1730.     ASPrint(M4Name, stream, strlen(M4Name));
  1731.     stream << dchar;
  1732.   }
  1733.   if(M5Name != 0) {
  1734.     ASPrint(M5Name, stream, strlen(M5Name));
  1735.     stream << dchar;
  1736.   }
  1737.   if(M6Name != 0) {
  1738.     ASPrint(M6Name, stream, strlen(M6Name));
  1739.     stream << dchar;
  1740.   }
  1741.   if(M7Name != 0) {
  1742.     ASPrint(M7Name, stream, strlen(M7Name));
  1743.     stream << dchar;
  1744.   }
  1745.   if(M8Name != 0) {
  1746.     ASPrint(M8Name, stream, strlen(M8Name));
  1747.     stream << dchar;
  1748.   }
  1749.   if(Comments != 0) {
  1750.     ASPrint(Comments, stream, strlen(Comments));
  1751.   }
  1752.   stream << asLineFeed;
  1753.   
  1754.   int exports = 0;
  1755.  
  1756.   LoadIndexKeys();
  1757.   
  1758.   dllistptr = dllist->GetFront();
  1759.   while(!dllist->IsHeader(dllistptr)) {
  1760.     strdb.ReadObject(dllistptr->Data.object_address);
  1761.     if(KeyName != 0) {
  1762.       ASPrint(strdb.GetKM(), filter, stream, strlen(strdb.GetKM()));
  1763.       stream << dchar;
  1764.     }
  1765.     if(M2Name != 0) {
  1766.       if(!*strdb.GetM2()) ASPrint(Fill, stream, strlen(Fill));
  1767.       else ASPrint(strdb.GetM2(), filter, stream, strlen(strdb.GetM2()));
  1768.       stream << dchar;
  1769.     }
  1770.     if(M3Name != 0) {
  1771.       if(!*strdb.GetM3()) ASPrint(Fill, stream, strlen(Fill));
  1772.       else ASPrint(strdb.GetM3(), filter, stream, strlen(strdb.GetM3()));
  1773.       stream << dchar;
  1774.     }
  1775.     if(M4Name != 0) {
  1776.       if(!*strdb.GetM4()) ASPrint(Fill, stream, strlen(Fill));
  1777.       else ASPrint(strdb.GetM4(), filter, stream, strlen(strdb.GetM4()));
  1778.       stream << dchar;
  1779.     }
  1780.     if(M5Name != 0) {
  1781.       if(!*strdb.GetM5()) ASPrint(Fill, stream, strlen(Fill));
  1782.       else ASPrint(strdb.GetM5(), filter, stream, strlen(strdb.GetM5()));
  1783.       stream << dchar;
  1784.     }
  1785.     if(M6Name != 0) {
  1786.       if(!*strdb.GetM6()) ASPrint(Fill, stream, strlen(Fill));
  1787.       else ASPrint(strdb.GetM6(), filter, stream, strlen(strdb.GetM6()));
  1788.       stream << dchar;
  1789.     }
  1790.     if(M7Name != 0) {
  1791.       if(!*strdb.GetM7()) ASPrint(Fill, stream, strlen(Fill));
  1792.       else ASPrint(strdb.GetM7(), filter, stream, strlen(strdb.GetM7()));
  1793.       stream << dchar;
  1794.     }
  1795.     if(M8Name != 0) {
  1796.       if(!*strdb.GetM8()) ASPrint(Fill, stream, strlen(Fill));
  1797.       else ASPrint(strdb.GetM8(), filter, stream, strlen(strdb.GetM8()));
  1798.       stream << dchar;
  1799.     }
  1800.     if(Comments != 0) {
  1801.       if(!*strdb.GetCM()) ASPrint(Fill, stream, strlen(Fill));
  1802.       else ASPrint(strdb.GetCM(), filter, stream, strlen(strdb.GetCM()));
  1803.     }
  1804.     stream << asLineFeed;
  1805.     exports++;
  1806.     dllistptr = dllistptr->GetNext(); 
  1807.   }
  1808.  
  1809.   dllist->Clear(); 
  1810.   terminal->Write("Exported ", p->XPos(), p->YOffset(2));
  1811.   terminal->Write(exports);
  1812.   terminal->Write(" items.");
  1813.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  1814.   delete p;          // Free the Coords pointer
  1815.   stream.close();
  1816. }
  1817.  
  1818. void ImportFromASCII()
  1819. {
  1820.   if(KeyName == 0) return;
  1821.  
  1822.   if(!AdminRights) {
  1823.     terminal->ClearScreen();
  1824.     terminal->Write("You do not have Admin User Privileges", 0, 1);
  1825.     terminal->AnyKey(0, 2);
  1826.     return;
  1827.   }
  1828.  
  1829.   char buf[CBuf];
  1830.   char words[MAXWORDS][MAXWORDLENGTH];
  1831.   int num;
  1832.   const int MaxLine = 512;
  1833.   char LineBuffer[MaxLine];
  1834.   char *sbuf;
  1835.   char *FileName;
  1836.   const char dchar = '\t';  // Text delimiter
  1837.  
  1838.   terminal->ClearScreen();
  1839.   Coords *p = new Coords(0, 0);
  1840.  
  1841.   terminal->Write("Importing database from ASCII file delimited by tabs",
  1842.           p->XPos(), p->YPos());
  1843.  
  1844.   terminal->Write("Enter file name to import from: ",
  1845.           p->XPos(), p->YOffset(2));
  1846.   terminal->GetString(buf);
  1847.   char *tmp = new char[strlen(buf)+1];
  1848.   tmp[strlen(buf)] = '\0';
  1849.   strcpy(tmp, buf);
  1850.   
  1851.   if(!VBDFile::Exists(tmp)) {
  1852.     terminal->Write("File: ",
  1853.             p->XPos(), p->YOffset(2));
  1854.     terminal->Write(tmp);
  1855.     terminal->Write(" does not exists.");
  1856.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  1857.     delete p;
  1858.     delete[] tmp;
  1859.     return;
  1860.   }
  1861.  
  1862.   FileName = tmp;
  1863.   ifstream stream(FileName, ios::in|ios::nocreate);
  1864.   terminal->Write("Importing database from: ",
  1865.           p->XPos(), p->YOffset(2));
  1866.   terminal->Write(FileName);
  1867.   
  1868.   if(!stream) { // Could not open the stream
  1869.     terminal->Write("Could not open file: ",
  1870.             p->XPos(), p->YOffset(2));
  1871.     terminal->Write(FileName);
  1872.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  1873.     delete[] tmp;
  1874.     delete p; // Free the Coords pointer
  1875.     return; 
  1876.   }
  1877.  
  1878.   terminal->Write("Importing...", p->XPos(), p->YOffset(2));
  1879.  
  1880.   ChSNode *listptr; // Linked list node pointer
  1881.   ChSList list;     // Linked list
  1882.   
  1883.   while(!stream.eof())
  1884.   {
  1885.     // Read in file line by line
  1886.     stream.getline(LineBuffer, MaxLine);
  1887.  
  1888.     // Allocate memory for temporary holding buffer
  1889.     sbuf = new char[strlen(LineBuffer)+1];
  1890.     
  1891.     // Copy contents of the array to temporary holding buffer
  1892.     strcpy(sbuf, LineBuffer);
  1893.  
  1894.     // Load file data into singly-linked list
  1895.     listptr = list.Store(sbuf); 
  1896.  
  1897.     if(!listptr) { // Out of memory
  1898.       stream.close();
  1899.       delete[] sbuf;
  1900.       list.Clear();
  1901.       return;
  1902.    }
  1903.   }
  1904.   stream.close();
  1905.   delete[] sbuf;
  1906.   
  1907.   StrDB strdb(DB);
  1908.   StrDB strdba(DB);
  1909.   StrDB ob(DB);
  1910.   
  1911.   int linecount = 0;
  1912.   int imports = 0;
  1913.   int updates = 0;
  1914.   int updateall = 0;
  1915.   int ObjectItems = 1; // Number of class data members 
  1916.   int x_prev, y_prev, c;
  1917.   FAU addr;
  1918.   
  1919.   // Calculate the number of object items
  1920.   if(M2Name != 0) ObjectItems++;
  1921.   if(M3Name != 0) ObjectItems++;
  1922.   if(M4Name != 0) ObjectItems++;
  1923.   if(M5Name != 0) ObjectItems++;
  1924.   if(M6Name != 0) ObjectItems++;
  1925.   if(M7Name != 0) ObjectItems++;
  1926.   if(M8Name != 0) ObjectItems++;
  1927.   if(Comments != 0) ObjectItems++;
  1928.  
  1929.   listptr = list.GetFront();
  1930.   while(!list.IsHeader(listptr)) {
  1931.     if(parse(listptr->Data, words, &num, dchar) == 1) {
  1932.       terminal->Write("Parse error!", p->XPos(), p->YOffset(2));
  1933.       break;
  1934.     }
  1935.  
  1936.     linecount++;
  1937.     if(num != ObjectItems && (num != 0 && num != 1)) {
  1938.       x_prev = p->XPos(); y_prev = p->YPos();
  1939.       terminal->Write("Error in ", p->XPos(), p->YOffset(2));
  1940.       terminal->Write(FileName);
  1941.       terminal->Write(" import file!");
  1942.       if(num > ObjectItems) 
  1943.     terminal->Write("To many items on line: ", p->XPos(), p->YOffset(2));
  1944.       if(num < ObjectItems) 
  1945.     terminal->Write("Not enough items on line: ",
  1946.             p->XPos(), p->YOffset(2));
  1947.       terminal->Write(linecount);
  1948.       terminal->Write("(X)-Exit, Any other key to continue",
  1949.             p->XPos(), p->YOffset(2));
  1950.       c = terminal->GetChar();
  1951.       switch(c) {
  1952.     case 'x': case 'X':
  1953.       delete p;          // Free the Coords pointer
  1954.       delete[] tmp;
  1955.       list.Clear();
  1956.       return;
  1957.     default:
  1958.       break;
  1959.       }
  1960.       terminal->ClearLine(p->XPos(), p->YPos());
  1961.       terminal->ClearLine(p->XPos(), p->YPos()-4);
  1962.       terminal->ClearLine(p->XPos(), p->YPos()-2);
  1963.       p->SetXY(x_prev, y_prev);
  1964.     }
  1965.  
  1966.     if(num == ObjectItems && *words[0] != 0) {
  1967.       strdb.SetKM(words[0]);
  1968.       if(M2Name != 0) strdb.SetM2(words[1]);
  1969.       if(M3Name != 0) strdb.SetM3(words[2]);
  1970.       if(M4Name != 0) strdb.SetM4(words[3]);
  1971.       if(M5Name != 0) strdb.SetM5(words[4]);
  1972.       if(M6Name != 0) strdb.SetM6(words[5]);
  1973.       if(M7Name != 0) strdb.SetM7(words[6]);
  1974.       if(M8Name != 0) strdb.SetM8(words[7]);
  1975.       if(Comments != 0) strdb.SetCM(words[8]);
  1976.       strdba.SetKM(strdb.GetKM());
  1977.       addr = strdba.FindObject();
  1978.       if(addr) { 
  1979.     x_prev = p->XPos(); y_prev = p->YPos();
  1980.     if(updateall == 0) {
  1981.       terminal->Write(strdb.GetKM(), p->XPos(), p->YOffset(2));
  1982.       terminal->Write(" entry already exists."); 
  1983.       terminal->Write("(U)-Update, (A)-Update all, (X)-Exit",
  1984.               p->XPos(), p->YOffset(2));
  1985.       terminal->Write(", Any other key to continue");
  1986.       c = terminal->GetChar();
  1987.     }
  1988.     if(updateall == 1) c = 'a';
  1989.     switch(c) {
  1990.       case 'a': case 'A':
  1991.         updateall = 1;
  1992.         updates++;
  1993.         ob.Copy(strdba);
  1994.             if(strdb.FullCompare(ob)) break; // The object has not changed
  1995.         ob.DeleteObject(); 
  1996.             strdb.AddObject(0);
  1997.         break;
  1998.       case 'u': case 'U': 
  1999.         updates++;
  2000.         ob.Copy(strdba);
  2001.             if(strdb.FullCompare(ob)) break; // The object has not changed
  2002.         ob.DeleteObject();
  2003.             strdb.AddObject(0);
  2004.          break;
  2005.       case 'x': case 'X':
  2006.         delete p;          // Free the Coords pointer
  2007.         delete[] tmp;
  2008.         list.Clear();
  2009.         return;
  2010.       default:
  2011.         break;
  2012.     }
  2013.     if(updateall == 1) {
  2014.       p->SetXY(x_prev, y_prev);
  2015.       terminal->ClearLine(x_prev, y_prev+2);
  2016.       terminal->ClearLine(x_prev, y_prev+4);
  2017.       terminal->Write("Updating entry for: ", p->XPos(), p->YOffset(2)); 
  2018.       terminal->Write(strdb.GetKM(), p->XPos(), p->YOffset(2)); 
  2019.       Sleep((clock_t)1);
  2020.       terminal->ClearLine(p->XPos(), p->YPos());
  2021.       terminal->ClearLine(p->XPos(), p->YPos()-2);
  2022.       p->SetXY(x_prev, y_prev);
  2023.       terminal->MoveCursor(x_prev, y_prev);
  2024.     }
  2025.     else {
  2026.       terminal->ClearLine(p->XPos(), p->YPos());
  2027.       terminal->ClearLine(p->XPos(), p->YPos()-2);
  2028.       p->SetXY(x_prev, y_prev);
  2029.       terminal->MoveCursor(x_prev, y_prev);
  2030.     }
  2031.       }
  2032.       else {
  2033.     // Ensure that the template does not get added to the file
  2034.     if(CaseICmp(KeyName, words[0]) != 0) {
  2035.       FAU addr = strdb.AddObject(0); // Write the object to the file
  2036.       imports++;
  2037.       if(!addr) {
  2038.         x_prev = p->XPos(); y_prev = p->YPos();
  2039.         terminal->Write("Could not add:", p->XPos(), p->YOffset(2));
  2040.         terminal->Write(strdb.GetKM());
  2041.         terminal->Write(" to database");
  2042.         terminal->AnyKey(p->XPos(), p->YOffset(2));
  2043.         terminal->ClearLine(p->XPos(), p->YPos());
  2044.         terminal->ClearLine(p->XPos(), p->YPos()-2);
  2045.         p->SetXY(x_prev, y_prev);
  2046.         imports--;
  2047.       }
  2048.     }
  2049.       }
  2050.     }
  2051.     listptr = listptr->GetNext();
  2052.   }
  2053.  
  2054.   terminal->Write("Imported ", p->XPos(), p->YOffset(2));
  2055.   terminal->Write(imports);
  2056.   terminal->Write(" items.");
  2057.   if(updates) {
  2058.     terminal->Write("Updated ", p->XPos(), p->YOffset(2));
  2059.     terminal->Write(updates);
  2060.     terminal->Write(" items.");
  2061.   }
  2062.   
  2063.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  2064.   delete p;          // Free the Coords pointer
  2065.   delete[] tmp;
  2066.   list.Clear();
  2067. }
  2068.  
  2069. void BackUp()
  2070. {
  2071.   if(DB->RebuildIndex()) {
  2072.     terminal->Write("The index file needs to be rebuilt.", 0, 1);
  2073.     terminal->AnyKey(0, 2);
  2074.     return;
  2075.   }
  2076.  
  2077.   char buf[CBuf];
  2078.   char *FileName;
  2079.  
  2080.   terminal->ClearScreen();
  2081.   Coords *p = new Coords(0, 0);
  2082.  
  2083.   terminal->Write("Backing up the database to another file",
  2084.           p->XPos(), p->YPos());
  2085.  
  2086.   terminal->Write("Enter new file name to create: ",
  2087.           p->XPos(), p->YOffset(2));
  2088.   terminal->GetString(buf);
  2089.  
  2090.   char *tmp = new char[strlen(buf)+1];
  2091.   tmp[strlen(buf)] = '\0';
  2092.   strcpy(tmp, buf);
  2093.   
  2094.   if(VBDFile::Exists(tmp)) {
  2095.     terminal->Write("File: ",
  2096.             p->XPos(), p->YOffset(2));
  2097.     terminal->Write(tmp);
  2098.     terminal->Write(" already exists.");
  2099.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2100.     delete p;
  2101.     delete[] tmp;
  2102.     return;
  2103.   }
  2104.  
  2105.   FileName = tmp;
  2106.   POD newdb(FileName, FileName);
  2107.   int items = 0;
  2108.   StrDB strdb(&newdb);
  2109.   StrDB strdb_old(DB);
  2110.  
  2111.   FAU oa;          // Object Address
  2112.   VBHeader vb;     // Variable Block Header
  2113.   ObjectHeader oh; // Object Header
  2114.  
  2115.   FAU vbdfileEOF = DB->OpenDatabase()->GetEOF();
  2116.   FAU addr = 0;
  2117.   addr = DB->OpenDatabase()->FindFirstVB(addr); // Search the entire file
  2118.  
  2119.   if(addr == 0) return; // No variable blocks found in file
  2120.  
  2121.   while(1) { 
  2122.     if(addr >= vbdfileEOF) break;
  2123.     DB->OpenDatabase()->Read(&vb, sizeof(VBHeader), addr);
  2124.     if(vb.CkWord == CheckWord) {
  2125.       if((__SBYTE__)vb.Status == NormalVB) {
  2126.     oa = addr + sizeof(VBHeader);
  2127.     DB->OpenDatabase()->Read(&oh, sizeof(ObjectHeader), oa);
  2128.     if(oh.ClassID == strdb.GetClassID()) { 
  2129.       strdb_old.ReadObject(oa);
  2130.       strdb.Copy(strdb_old);
  2131.       strdb.AddObject(0);
  2132.       items++;
  2133.     }
  2134.       }
  2135.       addr = addr + vb.Length; // Goto the next variable block
  2136.     }
  2137.     else {
  2138.       addr = DB->OpenDatabase()->VBSearch(addr); 
  2139.       if(!addr) break;
  2140.     }
  2141.   }
  2142.   
  2143.   terminal->Write("Backed up ",
  2144.           p->XPos(), p->YOffset(2));
  2145.   terminal->Write(items);
  2146.   terminal->Write(" objects to ");
  2147.   terminal->Write(tmp);
  2148.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  2149.  
  2150.   delete[] tmp;
  2151.   delete p;
  2152. }
  2153.  
  2154. void Merge()
  2155. {
  2156.   if(!AdminRights) {
  2157.     terminal->ClearScreen();
  2158.     terminal->Write("You do not have Admin User Privileges", 0, 1);
  2159.     terminal->AnyKey(0, 2);
  2160.     return;
  2161.   }
  2162.  
  2163.   char buf[CBuf];
  2164.   char *FileName;
  2165.   
  2166.   terminal->ClearScreen();
  2167.   Coords *p = new Coords(0, 0);
  2168.  
  2169.   terminal->Write("Merging the contents of another database", 
  2170.           p->XPos(), p->YPos());
  2171.  
  2172.   terminal->Write("Enter file name to merge: ",
  2173.           p->XPos(), p->YOffset(2));
  2174.   terminal->GetString(buf);
  2175.   char *tmp = new char[strlen(buf)+1];
  2176.   tmp[strlen(buf)] = '\0';
  2177.   strcpy(tmp, buf);
  2178.   
  2179.   if(!VBDFile::Exists(tmp)) {
  2180.     terminal->Write("File: ",
  2181.             p->XPos(), p->YOffset(2));
  2182.     terminal->Write(tmp);
  2183.     terminal->Write(" does not exists.");
  2184.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2185.     delete p;
  2186.     delete[] tmp;
  2187.     return;
  2188.   }
  2189.  
  2190.   FileName = tmp;
  2191.   POD *newdb = new POD(FileName, FileName, ROMode);
  2192.  
  2193.   StrDB strdb(newdb);
  2194.   StrDB strdba(DB);
  2195.   StrDB ob(DB);
  2196.   FAU addr;
  2197.   FAU existing;
  2198.   
  2199.   int x_prev, y_prev, c;
  2200.   int imports = 0;
  2201.   int updates = 0;
  2202.   int updateall = 0;
  2203.   
  2204.   FAU oa;          // Object Address
  2205.   VBHeader vb;     // Variable Block Header
  2206.   ObjectHeader oh; // Object Header
  2207.  
  2208.   FAU vbdfileEOF = newdb->OpenDatabase()->GetEOF();
  2209.   
  2210.   addr = 0;
  2211.   addr = newdb->OpenDatabase()->FindFirstVB(addr); // Search the entire file
  2212.  
  2213.   if(addr == 0) {
  2214.     terminal->Write("No variable blocks found in file: ",
  2215.             p->XPos(), p->YOffset(2));
  2216.     terminal->Write(tmp);
  2217.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2218.     delete p;
  2219.     delete[] tmp;
  2220.     return;
  2221.   }
  2222.   
  2223.   terminal->Write("Merging...", p->XPos(), p->YOffset(2));
  2224.   
  2225.   while(1) { 
  2226.     if(addr >= vbdfileEOF) break;
  2227.     newdb->OpenDatabase()->Read(&vb, sizeof(VBHeader), addr);
  2228.     if(vb.CkWord == CheckWord) {
  2229.       if((__SBYTE__)vb.Status == NormalVB) {
  2230.     oa = addr + sizeof(VBHeader);
  2231.     newdb->OpenDatabase()->Read(&oh, sizeof(ObjectHeader), oa);
  2232.     if(oh.ClassID == strdb.GetClassID()) { 
  2233.       strdb.ReadObject(oa);
  2234.       strdba.SetKM(strdb.GetKM());
  2235.       existing = strdba.FindObject();
  2236.       if(existing) {
  2237.         x_prev = p->XPos(); y_prev = p->YPos();
  2238.         if(updateall == 0) {
  2239.           terminal->Write(strdb.GetKM(), p->XPos(), p->YOffset(2));
  2240.           terminal->Write(" entry already exists."); 
  2241.           terminal->Write("(U)-Update, (A)-Update all, (X)-Exit",
  2242.                   p->XPos(), p->YOffset(2));
  2243.           terminal->Write(", Any other key to continue");
  2244.           c = terminal->GetChar();
  2245.         }
  2246.         if(updateall == 1) c = 'a';
  2247.         switch(c) {
  2248.           case 'a': case 'A': 
  2249.         updateall = 1;
  2250.         updates++;
  2251.         ob.Copy(strdb);
  2252.         if(strdb.FullCompare(ob)) break; // The object has not changed
  2253.         ob.DeleteObject();
  2254.         ob.Copy(strdb);
  2255.         ob.AddObject(0);
  2256.         break;
  2257.           case 'u': case 'U': 
  2258.         updates++;
  2259.         ob.Copy(strdb);
  2260.         if(strdb.FullCompare(ob)) break; // The object has not changed
  2261.         ob.DeleteObject();
  2262.         ob.Copy(strdb);
  2263.         ob.AddObject(0);
  2264.         break;
  2265.           case 'x': case 'X':
  2266.         delete newdb;
  2267.         delete p;
  2268.         delete[] tmp;
  2269.         return;
  2270.           default:
  2271.         break;
  2272.         }
  2273.         if(updateall == 1) {
  2274.           p->SetXY(x_prev, y_prev);
  2275.           terminal->ClearLine(x_prev, y_prev+1);
  2276.           terminal->ClearLine(x_prev, y_prev+4);
  2277.           terminal->Write("Updating entry for: ",
  2278.                   p->XPos(), p->YOffset(2)); 
  2279.           terminal->Write(strdb.GetKM(), p->XPos(), p->YOffset(2)); 
  2280.           Sleep((clock_t)1);
  2281.           terminal->ClearLine(p->XPos(), p->YPos());
  2282.           terminal->ClearLine(p->XPos(), p->YPos()-2);
  2283.           p->SetXY(x_prev, y_prev);
  2284.           terminal->MoveCursor(x_prev, y_prev);
  2285.         }
  2286.         else {
  2287.           terminal->ClearLine(p->XPos(), p->YPos());
  2288.           terminal->ClearLine(p->XPos(), p->YPos()-2);
  2289.           p->SetXY(x_prev, y_prev);
  2290.           terminal->MoveCursor(x_prev, y_prev);
  2291.         }
  2292.       }
  2293.       else {
  2294.         strdba.Copy(strdb);
  2295.         FAU rvaddr = strdba.AddObject(0); // Write the object to the file
  2296.         imports++;
  2297.         if(!rvaddr) {
  2298.           x_prev = p->XPos(); y_prev = p->YPos();
  2299.           terminal->Write("Could not add:", p->XPos(), p->YOffset(2));
  2300.           terminal->Write(ob.GetKM());
  2301.           terminal->Write(" to database");
  2302.           terminal->AnyKey(p->XPos(), p->YOffset(2));
  2303.           terminal->ClearLine(p->XPos(), p->YPos());
  2304.           terminal->ClearLine(p->XPos(), p->YPos()-2);
  2305.           p->SetXY(x_prev, y_prev);
  2306.           imports--;
  2307.         }
  2308.       }
  2309.     }
  2310.       }
  2311.       addr = addr + vb.Length; // Goto the next variable block
  2312.     }
  2313.     else {
  2314.       addr = newdb->OpenDatabase()->VBSearch(addr); 
  2315.       if(!addr) break;
  2316.     }
  2317.   }
  2318.   
  2319.   terminal->Write("Imported ", p->XPos(), p->YOffset(2));
  2320.   terminal->Write(imports);
  2321.   terminal->Write(" items.");
  2322.   if(updates) {
  2323.     terminal->Write("Updated ", p->XPos(), p->YOffset(2));
  2324.     terminal->Write(updates);
  2325.     terminal->Write(" items.");
  2326.   }
  2327.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  2328.  
  2329.   delete newdb;
  2330.   delete p;
  2331.   delete[] tmp;
  2332. }
  2333.  
  2334. void CreateTemplate()
  2335. {
  2336.   char buf[CBuf];
  2337.   char *FileName;
  2338.   const char dchar = '\t';   // Text delimiter
  2339.  
  2340.   terminal->ClearScreen();
  2341.   Coords *p = new Coords(0, 0);
  2342.  
  2343.   terminal->Write("Creating template file delimited by tabs",
  2344.           p->XPos(), p->YPos());
  2345.  
  2346.   terminal->Write("Enter file name to create: ",
  2347.           p->XPos(), p->YOffset(2));
  2348.   terminal->GetString(buf);
  2349.  
  2350.   char *tmp = new char[strlen(buf)+1];
  2351.   tmp[strlen(buf)] = '\0';
  2352.   strcpy(tmp, buf);
  2353.   
  2354.   if(VBDFile::Exists(tmp)) {
  2355.     terminal->Write("File: ",
  2356.             p->XPos(), p->YOffset(2));
  2357.     terminal->Write(tmp);
  2358.     terminal->Write(" already exists.");
  2359.     int yn = terminal->YesNo("Overwrite it (y/n)?", p->XPos(), p->YOffset(2));
  2360.     if(!yn) {
  2361.       delete p;
  2362.       delete[] tmp;
  2363.       return;
  2364.     }
  2365.   }
  2366.  
  2367.   FileName = tmp;
  2368.   delete[] tmp;
  2369.   
  2370.   ofstream stream(FileName, ios::out); // Open file and truncate it
  2371.   terminal->Write("Creating template file: ",
  2372.           p->XPos(), p->YOffset(2));
  2373.   terminal->Write(FileName);
  2374.   
  2375.   if(!stream) { // Could not open the stream
  2376.     terminal->Write("Could not write to: ",
  2377.             p->XPos(), p->YOffset(2));
  2378.     terminal->Write(FileName);
  2379.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2380.     delete p; // Free the Coords pointer
  2381.     return; 
  2382.   }
  2383.  
  2384.   if(KeyName != 0) {
  2385.     ASPrint(KeyName, stream, strlen(KeyName));
  2386.     stream << dchar;
  2387.   }
  2388.   if(M2Name != 0) {
  2389.     ASPrint(M2Name, stream, strlen(M2Name));
  2390.     stream << dchar;
  2391.   }
  2392.   if(M3Name != 0) {
  2393.     ASPrint(M3Name, stream, strlen(M3Name));
  2394.     stream << dchar;
  2395.   }
  2396.   if(M4Name != 0) {
  2397.     ASPrint(M4Name, stream, strlen(M4Name));
  2398.     stream << dchar;
  2399.   }
  2400.   if(M5Name != 0) {
  2401.     ASPrint(M5Name, stream, strlen(M5Name));
  2402.     stream << dchar;
  2403.   }
  2404.   if(M6Name != 0) {
  2405.     ASPrint(M6Name, stream, strlen(M6Name));
  2406.     stream << dchar;
  2407.   }
  2408.   if(M7Name != 0) {
  2409.     ASPrint(M7Name, stream, strlen(M7Name));
  2410.     stream << dchar;
  2411.   }
  2412.   if(M8Name != 0) {
  2413.     ASPrint(M8Name, stream, strlen(M8Name));
  2414.     stream << dchar;
  2415.   }
  2416.   if(Comments != 0) {
  2417.     ASPrint(Comments, stream, strlen(Comments));
  2418.   }
  2419.   stream << asLineFeed;
  2420.   
  2421.   terminal->Write("Finished", p->XPos(), p->YOffset(2));
  2422.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  2423.   delete p;          // Free the Coords pointer
  2424.   stream.close();
  2425. }
  2426.  
  2427. void CompareIndexFile()
  2428. {
  2429.   terminal->ClearScreen();
  2430.   Coords *p = new Coords(0, 0);
  2431.  
  2432.   if(!DB->UsingIndex()) {
  2433.     terminal->Write("No index is being used for this database.",
  2434.           p->XPos(), p->YPos());
  2435.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2436.     delete p;          // Free the Coords pointer
  2437.     return;
  2438.   }
  2439.  
  2440.   terminal->Write("Comparing the index file to the data file...",
  2441.           p->XPos(), p->YPos());
  2442.  
  2443.   StrDB strdb(DB);
  2444.  
  2445.   int rv = strdb.CompareIndex();
  2446.   if(!rv) {
  2447.     terminal->Write("The index file does not match the data file!",
  2448.           p->XPos(), p->YOffset(2));
  2449.     terminal->Write("The index file needs to be rebuilt.",
  2450.           p->XPos(), p->YOffset(1));
  2451.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2452.     delete p;          // Free the Coords pointer
  2453.     return;
  2454.   }
  2455.  
  2456.   terminal->Write("The index file checks good.",
  2457.           p->XPos(), p->YOffset(2));
  2458.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  2459.   
  2460.   delete p;          // Free the Coords pointer
  2461.   return;
  2462. }
  2463.  
  2464. void RebuildIndexFile()
  2465. {
  2466.   char buf[CBuf];
  2467.   char *FileName;
  2468.  
  2469.   terminal->ClearScreen();
  2470.   Coords *p = new Coords(0, 0);
  2471.  
  2472.   if(!DB->UsingIndex()) {
  2473.     terminal->Write("No index is being used for this database.",
  2474.           p->XPos(), p->YPos());
  2475.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2476.     delete p;          // Free the Coords pointer
  2477.     return;
  2478.   }
  2479.  
  2480.   terminal->Write("Rebuilding the index file for this database.",
  2481.           p->XPos(), p->YPos());
  2482.  
  2483.   terminal->Write("Enter new file name to create: ",
  2484.           p->XPos(), p->YOffset(2));
  2485.   terminal->GetString(buf);
  2486.  
  2487.   char *tmp = new char[strlen(buf)+1];
  2488.   tmp[strlen(buf)] = '\0';
  2489.   strcpy(tmp, buf);
  2490.   
  2491.   if(VBDFile::Exists(tmp)) {
  2492.     terminal->Write("File: ",
  2493.             p->XPos(), p->YOffset(2));
  2494.     terminal->Write(tmp);
  2495.     terminal->Write(" already exists.");
  2496.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2497.     delete p;
  2498.     delete[] tmp;
  2499.     return;
  2500.   }
  2501.  
  2502.   terminal->Write("Rebuilding the index file... ",
  2503.           p->XPos(), p->YOffset(2));
  2504.  
  2505.   StrDB strdb(DB);
  2506.   int rv = strdb.RebuildIndexFile(tmp);
  2507.   if(!rv) {
  2508.     terminal->Write("The index file was not rebuilt!",
  2509.             p->XPos(), p->YOffset(2));
  2510.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2511.     delete p;
  2512.     delete[] tmp;
  2513.     return;
  2514.   }
  2515.  
  2516.     terminal->Write("The index file was rebuilt.",
  2517.             p->XPos(), p->YOffset(2));
  2518.     terminal->Write("A new index file named ",
  2519.             p->XPos(), p->YOffset(1));
  2520.     terminal->Write(tmp);
  2521.     terminal->Write(" was created.");
  2522.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2523.     delete p;
  2524.     delete[] tmp;
  2525. }
  2526.  
  2527. void StrDBSearch(StrDB &strdb, StrDBItem item, UString &str,
  2528.          Coords *p, const char *wildcard)
  2529. {
  2530.   terminal->Write("Searching for ", p->XPos(), p->YOffset(2));
  2531.   terminal->Write(str.c_str());
  2532.  
  2533.   int offset;
  2534.   offset = ObjectsFound = 0;
  2535.  
  2536.   if(wildcard != 0) {
  2537.     while(1) { // Remove the wild card characters from the string
  2538.       offset = str.Find(wildcard, offset);
  2539.       if (offset == UString::NoMatch) break;
  2540.       str.DeleteAt(offset, strlen(wildcard));
  2541.       offset++;
  2542.     }
  2543.   }
  2544.  
  2545.   // Ensure that the memory buffers and the file data
  2546.   // stay in sync during multiple file access.
  2547.   DB->Index()->TestTree();
  2548.  
  2549.   dllist->Clear();
  2550.  
  2551.   if(wildcard != 0)
  2552.     BtreeSearch(DB->Index(), item, strdb, str, 1);
  2553.   else
  2554.     BtreeSearch(DB->Index(), item, strdb, str);
  2555.  
  2556.   if(ObjectsFound == 0) {
  2557.     terminal->Write("No matches found.", p->XPos(), p->YOffset(2));
  2558.     terminal->AnyKey(p->XPos(), p->YOffset(1));
  2559.     return;
  2560.   }
  2561.  
  2562.   if(ObjectsFound > 1) { // Found multiple matches
  2563.     terminal->Write("Found ", p->XPos(), p->YOffset(2));
  2564.     terminal->Write(ObjectsFound);
  2565.     terminal->Write(" matching.");
  2566.     terminal->AnyKey(p->XPos(), p->YOffset(1));
  2567.   }
  2568.   else {
  2569.     terminal->Write("Found matching entry for:  ", p->XPos(), p->YOffset(2));
  2570.     terminal->Write(str.c_str());
  2571.     terminal->AnyKey(p->XPos(), p->YOffset(1));
  2572.   }
  2573.  
  2574.   // Display all the matches
  2575.   dllistptr = dllist->GetFront();
  2576.   while(!dllist->IsHeader(dllistptr)) {
  2577.     terminal->ClearScreen();
  2578.     p->SetXY(0, 0);
  2579.     strdb.ReadObject(dllistptr->Data.object_address);
  2580.     DisplayObject(strdb, p);
  2581.     terminal->Write("(C)-Change, (D)-Delete, (P)-Print, (X)-Exit",
  2582.             p->XPos(), p->YOffset(2));
  2583.     terminal->Write(", Any other key to continue");
  2584.     int c = terminal->GetChar();
  2585.     switch(c) {
  2586.       case 'c': case 'C': 
  2587.     terminal->ClearScreen();
  2588.     p->SetXY(0, 0);
  2589.     strdb.ReadObject(dllistptr->Data.object_address);
  2590.         ChangeObject(strdb, p);
  2591.     break;
  2592.     
  2593.       case 'd': case 'D': {
  2594.     int yn = terminal->YesNo("Are you sure you want to delete (y/n)",
  2595.                  p->XPos(), p->YOffset(2));
  2596.     if(!yn) break;
  2597.     strdb.ReadObject(dllistptr->Data.object_address);
  2598.         strdb.DeleteObject();
  2599.     break;
  2600.       }
  2601.       
  2602.       case 'p': case 'P':
  2603.     strdb.ReadObject(dllistptr->Data.object_address);
  2604.     p->YOffset(1);
  2605.         PrintObject(strdb, p);
  2606.     break;
  2607.  
  2608.       case 'x': case 'X':
  2609.     dllist->Clear(); // Free dllist memory
  2610.     return;
  2611.  
  2612.       default:
  2613.     break;
  2614.     }
  2615.     dllistptr = dllistptr->GetNext();
  2616.   }
  2617.   dllist->Clear(); // Free dllist memory
  2618. }
  2619.  
  2620. int PrintPSItemBar(ofstream &stream, PostScriptDrv &psdrv,
  2621.             int x_offset, int char_offset, int cell_len)
  2622. {
  2623.   if(KeyName != 0) {
  2624.     psdrv.PrintLine((char *)KeyName, cell_len, stream);
  2625.     x_offset += char_offset;
  2626.   } 
  2627.   if(M2Name != 0) {
  2628.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2629.     psdrv.PrintLine((char *)M2Name, cell_len, stream);
  2630.     x_offset += char_offset;
  2631.   }
  2632.   
  2633.   if(M3Name != 0) {
  2634.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2635.     psdrv.PrintLine((char *)M3Name, cell_len, stream);
  2636.     x_offset += char_offset;
  2637.   }
  2638.  
  2639.   if(M4Name != 0) {
  2640.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2641.     psdrv.PrintLine((char *)M4Name, cell_len, stream);
  2642.     x_offset += char_offset;
  2643.   }
  2644.  
  2645.   if(M5Name != 0) {
  2646.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2647.     psdrv.PrintLine((char *)M5Name, cell_len, stream);
  2648.     x_offset += char_offset;
  2649.   }
  2650.  
  2651.   if(M6Name != 0) {
  2652.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2653.     psdrv.PrintLine((char *)M6Name, cell_len, stream);
  2654.     x_offset += char_offset;
  2655.   }
  2656.  
  2657.   if(M7Name != 0) {
  2658.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2659.     psdrv.PrintLine((char *)M7Name, cell_len, stream);
  2660.     x_offset += char_offset;
  2661.   }
  2662.  
  2663.   if(M8Name != 0) {
  2664.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2665.     psdrv.PrintLine((char *)M8Name, cell_len, stream);
  2666.     x_offset += char_offset;
  2667.   }
  2668.  
  2669.   if(Comments != 0) {
  2670.     psdrv.MoveTo(stream, x_offset, psdrv.row);
  2671.     psdrv.PrintLine((char *)Comments, cell_len, stream);
  2672.     x_offset += char_offset;
  2673.   }
  2674.   return x_offset;
  2675. }
  2676.  
  2677. void PostScriptPrint()
  2678. {
  2679.   Coords *p = new Coords(0, 0);
  2680.   terminal->ClearScreen();
  2681.   if(DB->RebuildIndex()) {
  2682.     terminal->Write("The index file needs to be rebuilt.",
  2683.             p->XPos(), p->YOffset(2));
  2684.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2685.     return;
  2686.   }
  2687.  
  2688.   char buf[CBuf];
  2689.   int i;
  2690.   
  2691.   // Setup the default values for user configurable PostScript parameters
  2692.   int cell_len = 19;    
  2693.   double font_size = 7; 
  2694.   int orientation = 1;
  2695.   const int DocNameLen = 255;
  2696.   char psDocName[DocNameLen];
  2697.   for(i = 0; i < DocNameLen; i++) psDocName[i] = 0;
  2698.   strcpy(psDocName, ProgramName);
  2699.  
  2700.   PostScriptDrv::PSPaperSizes paper_code = PostScriptDrv::LETTER_SIZE;
  2701.   PostScriptDrv::PSFonts item_font = PostScriptDrv::COURIER_BOLD_OBLIQUE;
  2702.   PostScriptDrv::PSFonts cell_font = PostScriptDrv::COURIER;
  2703.  
  2704.   // Load the PostScript configuration from the config file
  2705.   char *CurrentCfgFile;
  2706.   char *CfgFile;
  2707.   Config *CfgData = new Config;
  2708.  
  2709.   // Look for CfgFile name in environment
  2710.   if((CurrentCfgFile = getenv(EnvSetting)) == 0)
  2711.     CfgFile = (char *)DefaultCfgFile;
  2712.   else
  2713.     CfgFile = CurrentCfgFile;
  2714.  
  2715.   int FileStatus = CfgData->Load((char *)CfgFile);
  2716.   if(FileStatus) { // Found a valid config file
  2717. // *********************************************************** //
  2718. // Add all PostScript config file entries here
  2719. // *********************************************************** //
  2720.     int int_val = 0;
  2721.     double dfp_val = 0;
  2722.     char *str_val = 0;
  2723.  
  2724.     int_val = CfgData->GetIntValue("CellLength");
  2725.     if(int_val > 0) cell_len = int_val;
  2726.  
  2727.     dfp_val = CfgData->GetDFPValue("FontSize");
  2728.     if(dfp_val > 0) font_size = dfp_val;
  2729.  
  2730.     str_val = CfgData->GetStrValue("Orientation");
  2731.     if(str_val != 0) {
  2732.       if(strcmp(str_val, "PORTRAIT") == 0) orientation = 0;
  2733.       str_val = 0;
  2734.     }
  2735.     
  2736.     str_val = CfgData->GetStrValue("PaperSize");
  2737.     if(str_val != 0) {
  2738.       if(strcmp(str_val, "LETTER") == 0)
  2739.     paper_code = PostScriptDrv::LETTER_SIZE;
  2740.       if(strcmp(str_val, "LEGAL") == 0)
  2741.     paper_code = PostScriptDrv::LEGAL_SIZE;
  2742.       if(strcmp(str_val, "TABLOID") == 0)
  2743.     paper_code = PostScriptDrv::TABLOID_SIZE;
  2744.       if(strcmp(str_val, "A3") == 0) paper_code = PostScriptDrv::A3_SIZE;
  2745.       if(strcmp(str_val, "A4") == 0) paper_code = PostScriptDrv::A4_SIZE;
  2746.       str_val = 0;
  2747.     }
  2748.  
  2749.     str_val = CfgData->GetStrValue("ItemBarFont");
  2750.     if(str_val != 0) {
  2751.       if(strcmp(str_val, "COURIER") == 0)
  2752.     item_font = PostScriptDrv::COURIER;
  2753.       if(strcmp(str_val, "COURIER_BOLD") == 0)
  2754.     item_font = PostScriptDrv::COURIER_BOLD;
  2755.       if(strcmp(str_val, "COURIER_OBLIQUE") == 0)
  2756.     item_font = PostScriptDrv::COURIER_OBLIQUE;
  2757.       if(strcmp(str_val, "COURIER_BOLD_OBLIQUE") == 0)
  2758.     item_font = PostScriptDrv::COURIER_BOLD_OBLIQUE;
  2759.       str_val = 0;
  2760.     }
  2761.     
  2762.     str_val = CfgData->GetStrValue("CellFont");
  2763.     if(str_val != 0) {
  2764.       if(strcmp(str_val, "COURIER") == 0)
  2765.     cell_font = PostScriptDrv::COURIER;
  2766.       if(strcmp(str_val, "COURIER_BOLD") == 0)
  2767.     cell_font = PostScriptDrv::COURIER_BOLD;
  2768.       if(strcmp(str_val, "COURIER_OBLIQUE") == 0)
  2769.     cell_font = PostScriptDrv::COURIER_OBLIQUE;
  2770.       if(strcmp(str_val, "COURIER_BOLD_OBLIQUE") == 0)
  2771.     cell_font = PostScriptDrv::COURIER_BOLD_OBLIQUE;
  2772.     }
  2773.  
  2774.     str_val = CfgData->GetStrValue("psDocumentName");
  2775.     if(str_val != 0) {
  2776.       for(i = 0; i < DocNameLen; i++) psDocName[i] = 0;
  2777.       strcpy(psDocName, str_val);
  2778.     }
  2779. // *********************************************************** //    
  2780.   }
  2781.   CfgData->UnLoad(); // Unload the Config file from memory
  2782.  
  2783.   for(i = 0; i < CBuf; i++) buf[i] = 0;
  2784.   terminal->Write("Enter file name to print to: ",
  2785.           p->XPos(), p->YPos());
  2786.   terminal->GetString(buf);
  2787.   
  2788.   if(VBDFile::Exists(buf)) {
  2789.     terminal->Write("File: ",
  2790.             p->XPos(), p->YOffset(2));
  2791.     terminal->Write(buf);
  2792.     terminal->Write(" already exists.");
  2793.     int yn = terminal->YesNo("Overwrite it (y/n)?", p->XPos(), p->YOffset(2));
  2794.     if(!yn) {
  2795.       delete p;
  2796.       return;
  2797.     }
  2798.   }
  2799.  
  2800.   ofstream stream(buf, ios::out); // Open file and truncate it
  2801.   terminal->Write("Printing to: ",
  2802.           p->XPos(), p->YOffset(2));
  2803.   terminal->Write(buf);
  2804.   
  2805.   if(!stream) { // Could not open the stream
  2806.     terminal->Write("Could not write to: ",
  2807.             p->XPos(), p->YOffset(2));
  2808.     terminal->Write(buf);
  2809.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2810.     delete p; // Free the Coords pointer
  2811.     return; 
  2812.   }
  2813.  
  2814.   terminal->Write("Printing...", p->XPos(), p->YOffset(2));
  2815.             
  2816.   PostScriptDrv psdrv;
  2817.   psdrv.Copies(1);
  2818.  
  2819.   // Setup the PostScript driver
  2820.   psdrv.SetPaperSize(paper_code);
  2821.   psdrv.SetFont(cell_font, font_size);
  2822.   psdrv.UseHeader();
  2823.   if(orientation == 1) psdrv.LandScapeMode();
  2824.   psdrv.SetDocumentName(psDocName);
  2825.   char time_buf[255]; // Buffer used to hold time/date string
  2826.   GetSystemTime(time_buf);
  2827.   psdrv.SetDateString(time_buf);
  2828.   psdrv.DocumentSetup();
  2829.   psdrv.Prologue(stream);
  2830.   psdrv.MediaSetup(stream);
  2831.   StrDB strdb(DB);
  2832.   int char_offset = int((cell_len + 1) * psdrv.CharWidth());
  2833.   int x_offset;
  2834.   if(orientation == 0)
  2835.     x_offset = int(HEADER_OFFSET * PIXELS_PER_INCH);
  2836.   else
  2837.     x_offset = PRINTABLE_OFFSET_X;
  2838.  
  2839.   int lines = 4;
  2840.   psdrv.StartPage(psdrv.page_count + 1, stream);
  2841.   psdrv.row = psdrv.StartY();
  2842.   psdrv.MoveTo(stream, psdrv.StartX(), psdrv.row);
  2843.  
  2844.   psdrv.ChangeFont(stream, item_font, font_size);
  2845.   x_offset = PrintPSItemBar(stream, psdrv, x_offset, char_offset, cell_len);
  2846.   psdrv.ChangeFont(stream, cell_font, font_size);
  2847.   
  2848.   int line_points;
  2849.   if(orientation == 0)
  2850.     line_points = int(x_offset - (HEADER_OFFSET * PIXELS_PER_INCH));
  2851.   else
  2852.     line_points = x_offset - PRINTABLE_OFFSET_X;
  2853.  
  2854.   psdrv.row -= (int)psdrv.FontSize();
  2855.   lines++;
  2856.   psdrv.drawThickLine(stream, line_points, psdrv.StartX(), psdrv.row);
  2857.   psdrv.row -= THICK_LINE_WIDTH + psdrv.FontSize();
  2858.   lines++;
  2859.  
  2860.   LoadIndexKeys();
  2861.   
  2862.   dllistptr = dllist->GetFront();
  2863.   while(!dllist->IsHeader(dllistptr)) {
  2864.     strdb.ReadObject(dllistptr->Data.object_address);
  2865.     if(orientation == 0)
  2866.       x_offset = int(HEADER_OFFSET * PIXELS_PER_INCH);
  2867.     else
  2868.       x_offset = PRINTABLE_OFFSET_X;
  2869.  
  2870.     if(KeyName != 0) {
  2871.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2872.       psdrv.PrintLine(strdb.GetKM(), cell_len, stream);
  2873.       x_offset += char_offset;
  2874.     } 
  2875.     if(M2Name != 0) {
  2876.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2877.       psdrv.PrintLine(strdb.GetM2(), cell_len, stream);
  2878.       x_offset += char_offset;
  2879.     }
  2880.     
  2881.     if(M3Name != 0) {
  2882.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2883.       psdrv.PrintLine(strdb.GetM3(), cell_len, stream);
  2884.       x_offset += char_offset;
  2885.     }
  2886.     
  2887.     if(M4Name != 0) {
  2888.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2889.       psdrv.PrintLine(strdb.GetM4(), cell_len, stream);
  2890.     x_offset += char_offset;
  2891.     }
  2892.     
  2893.     if(M5Name != 0) {
  2894.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2895.       psdrv.PrintLine(strdb.GetM5(), cell_len, stream);
  2896.       x_offset += char_offset;
  2897.     }
  2898.     
  2899.     if(M6Name != 0) {
  2900.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2901.       psdrv.PrintLine(strdb.GetM6(), cell_len, stream);
  2902.       x_offset += char_offset;
  2903.     }
  2904.     
  2905.     if(M7Name != 0) {
  2906.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2907.       psdrv.PrintLine(strdb.GetM7(), cell_len, stream);
  2908.       x_offset += char_offset;
  2909.     }
  2910.     
  2911.     if(M8Name != 0) {
  2912.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2913.       psdrv.PrintLine(strdb.GetM8(), cell_len, stream);
  2914.       x_offset += char_offset;
  2915.     }
  2916.     
  2917.     if(Comments != 0) {
  2918.       psdrv.MoveTo(stream, x_offset, psdrv.row);
  2919.       psdrv.PrintLine(strdb.GetCM(), cell_len, stream);
  2920.       x_offset += char_offset;
  2921.     }
  2922.     psdrv.row -= psdrv.FontSize();
  2923.     lines++;
  2924.     if(orientation == 0)
  2925.       line_points = int(x_offset - (HEADER_OFFSET * PIXELS_PER_INCH));
  2926.     else
  2927.       line_points = x_offset - PRINTABLE_OFFSET_X;
  2928.     psdrv.drawLine(stream, line_points, psdrv.StartX(), psdrv.row);
  2929.     psdrv.row -= LINE_WIDTH + psdrv.FontSize();
  2930.     lines++; // Increment the line count
  2931.  
  2932.     if(lines >= psdrv.LinesPerPage()) {
  2933.       psdrv.EndPage(stream);
  2934.       psdrv.StartPage(psdrv.page_count + 1, stream);
  2935.       if(orientation == 0)
  2936.     x_offset = int(HEADER_OFFSET * PIXELS_PER_INCH);
  2937.       else
  2938.     x_offset = PRINTABLE_OFFSET_X;
  2939.       psdrv.row = psdrv.StartY();
  2940.       lines = 4;
  2941.       psdrv.MoveTo(stream, psdrv.StartX(), psdrv.row);
  2942.       psdrv.ChangeFont(stream, item_font, font_size);
  2943.       x_offset = PrintPSItemBar(stream, psdrv, x_offset,
  2944.                 char_offset, cell_len);
  2945.       psdrv.ChangeFont(stream, cell_font, font_size);
  2946.       if(orientation == 0)
  2947.     line_points = int(x_offset - (HEADER_OFFSET * PIXELS_PER_INCH));
  2948.       else
  2949.     line_points = x_offset - PRINTABLE_OFFSET_X;
  2950.       psdrv.row -= (int)psdrv.FontSize();
  2951.       lines++;
  2952.       psdrv.drawThickLine(stream, line_points, psdrv.StartX(), psdrv.row);
  2953.       psdrv.row -= THICK_LINE_WIDTH + psdrv.FontSize();
  2954.       lines ++;
  2955.     }
  2956.     dllistptr = dllistptr->GetNext(); 
  2957.   }
  2958.   psdrv.EndPage(stream);
  2959.   psdrv.Epilogue(stream, psdrv.page_count);
  2960.   
  2961.   dllist->Clear(); 
  2962.   terminal->Write("Finished", p->XPos(), p->YOffset(2));
  2963.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  2964.   delete p;          // Free the Coords pointer
  2965.   stream.close();
  2966. }
  2967.  
  2968. void HTMLPrint()
  2969. {
  2970.   Coords *p = new Coords(0, 0);
  2971.   terminal->ClearScreen();
  2972.   if(DB->RebuildIndex()) {
  2973.     terminal->Write("The index file needs to be rebuilt.",
  2974.             p->XPos(), p->YOffset(2));
  2975.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  2976.     return;
  2977.   }
  2978.  
  2979.   char buf[CBuf];
  2980.   int i;
  2981.   
  2982.   for(i = 0; i < CBuf; i++) buf[i] = 0;
  2983.   terminal->Write("Enter file name to print to: ",
  2984.           p->XPos(), p->YPos());
  2985.   terminal->GetString(buf);
  2986.   
  2987.   if(VBDFile::Exists(buf)) {
  2988.     terminal->Write("File: ",
  2989.             p->XPos(), p->YOffset(2));
  2990.     terminal->Write(buf);
  2991.     terminal->Write(" already exists.");
  2992.     int yn = terminal->YesNo("Overwrite it (y/n)?", p->XPos(), p->YOffset(2));
  2993.     if(!yn) {
  2994.       delete p;
  2995.       return;
  2996.     }
  2997.   }
  2998.  
  2999.   ofstream stream(buf, ios::out); // Open file and truncate it
  3000.   terminal->Write("Printing to: ",
  3001.           p->XPos(), p->YOffset(2));
  3002.   terminal->Write(buf);
  3003.   
  3004.   if(!stream) { // Could not open the stream
  3005.     terminal->Write("Could not write to: ",
  3006.             p->XPos(), p->YOffset(2));
  3007.     terminal->Write(buf);
  3008.     terminal->AnyKey(p->XPos(), p->YOffset(2));
  3009.     delete p; // Free the Coords pointer
  3010.     return; 
  3011.   }
  3012.  
  3013.   terminal->Write("Printing...", p->XPos(), p->YOffset(2));
  3014.   LoadIndexKeys();
  3015.  
  3016.   HyperText htm(stream);
  3017.   char date[255]; htm.GetSystemTime(date);
  3018.   htm << comment << "HTML file generated by: " << ProgramName << " version ";
  3019.   htm.precision(3);
  3020.   htm << VersionNumber << ecomment << endl;
  3021.   htm << comment << "File Creation date: " << date << ecomment << endl;
  3022.  
  3023.   htm.Prologue(ProgramName);
  3024.   htm.StartBody("BGCOLOR=\"#FFFFFF\"");
  3025.   htm.eat_space(); // Use non-breaking spaces
  3026.   htm.GenTable();
  3027.   int num_columns = 0;
  3028.  
  3029.   // Calculate the number of columns
  3030.   if(KeyName != 0) num_columns++; 
  3031.   if(M2Name != 0) num_columns++; 
  3032.   if(M3Name != 0) num_columns++; 
  3033.   if(M4Name != 0) num_columns++; 
  3034.   if(M5Name != 0) num_columns++; 
  3035.   if(M6Name != 0) num_columns++; 
  3036.   if(M7Name != 0) num_columns++; 
  3037.   if(M8Name != 0) num_columns++; 
  3038.   if(Comments != 0) num_columns++;
  3039.  
  3040.   // Write the table title
  3041.   htm.StartTableRow();
  3042.   htm.TableHeader("CENTER", num_columns, 1, 10);
  3043.   char sys_time[255];
  3044.   htm.GetSystemTime(sys_time);
  3045.   htm << ' ' << ProgramName << ' ' << br << ' ' << sys_time << ' ';
  3046.   htm.EndTableHeader();
  3047.   htm.EndTableRow();
  3048.   
  3049.   // Write the table headers
  3050.   htm.StartTableRow();
  3051.   if(KeyName != 0) {
  3052.     htm.TableHeader();
  3053.     htm << ' ' << KeyName << ' ';
  3054.     htm.EndTableHeader();
  3055.   } 
  3056.   if(M2Name != 0) {
  3057.     htm.TableHeader();
  3058.     htm << ' ' << M2Name << ' ';
  3059.     htm.EndTableHeader();
  3060.   }
  3061.   if(M3Name != 0) {
  3062.     htm.TableHeader();
  3063.     htm << ' ' << M3Name << ' ';
  3064.     htm.EndTableHeader();
  3065.   }
  3066.   if(M4Name != 0) {
  3067.     htm.TableHeader();
  3068.     htm << ' ' << M4Name << ' ';
  3069.     htm.EndTableHeader();
  3070.   }
  3071.   if(M5Name != 0) {
  3072.     htm.TableHeader();
  3073.     htm << ' ' << M5Name << ' ';
  3074.     htm.EndTableHeader();
  3075.   }
  3076.   if(M6Name != 0) {
  3077.     htm.TableHeader();
  3078.     htm << ' ' << M6Name << ' ';
  3079.     htm.EndTableHeader();
  3080.   }
  3081.   if(M7Name != 0) {
  3082.     htm.TableHeader();
  3083.     htm << ' ' << M7Name << ' ';
  3084.     htm.EndTableHeader();
  3085.   }
  3086.   if(M8Name != 0) {
  3087.     htm.TableHeader();
  3088.     htm << ' ' << M8Name << ' ';
  3089.     htm.EndTableHeader();
  3090.   }
  3091.   if(Comments != 0) {
  3092.     htm.TableHeader();
  3093.     htm << ' ' << Comments << ' ';
  3094.     htm.EndTableHeader();
  3095.   }
  3096.   htm.EndTableRow();
  3097.   
  3098.   StrDB strdb(DB);
  3099.   dllistptr = dllist->GetFront();
  3100.  
  3101.   while(!dllist->IsHeader(dllistptr)) {
  3102.     strdb.ReadObject(dllistptr->Data.object_address);
  3103.     htm.StartTableRow();
  3104.     if(KeyName != 0) {
  3105.       htm.TableData();
  3106.       htm << strdb.GetKM();
  3107.       htm.EndTableData();
  3108.     } 
  3109.     if(M2Name != 0) {
  3110.       htm.TableData();
  3111.       htm << strdb.GetM2() << ' ';
  3112.       htm.EndTableData();
  3113.     }
  3114.     if(M3Name != 0) {
  3115.       htm.TableData();
  3116.       htm << strdb.GetM3() << ' ';
  3117.       htm.EndTableData();
  3118.     }
  3119.     if(M4Name != 0) {
  3120.       htm.TableData();
  3121.       htm << strdb.GetM4() << ' ';
  3122.       htm.EndTableData();
  3123.     }
  3124.     if(M5Name != 0) {
  3125.       htm.TableData();
  3126.       htm << strdb.GetM5() << ' ';
  3127.       htm.EndTableData();
  3128.     }
  3129.     if(M6Name != 0) {
  3130.       htm.TableData();
  3131.       htm << strdb.GetM6() << ' ';
  3132.       htm.EndTableData();
  3133.     }
  3134.     if(M7Name != 0) {
  3135.       htm.TableData();
  3136.       htm << strdb.GetM7() << ' ';
  3137.       htm.EndTableData();
  3138.     }
  3139.     if(M8Name != 0) {
  3140.       htm.TableData();
  3141.       htm << strdb.GetM8() << ' ';
  3142.       htm.EndTableData();
  3143.     }
  3144.     if(Comments != 0) {
  3145.       htm.TableData();
  3146.       htm << strdb.GetCM() << ' ';
  3147.       htm.EndTableData();
  3148.     }
  3149.     htm.EndTableRow();
  3150.     dllistptr = dllistptr->GetNext();
  3151.   }
  3152.  
  3153.   htm.EndTable();
  3154.   htm.Epilogue();
  3155.   
  3156.   dllist->Clear(); 
  3157.   terminal->Write("Finished", p->XPos(), p->YOffset(2));
  3158.   terminal->AnyKey(p->XPos(), p->YOffset(2));
  3159.   delete p;          // Free the Coords pointer
  3160.   stream.close();
  3161. }
  3162.  
  3163. // Main prorgram thread
  3164. int main(int argc, char **argv)
  3165. {
  3166.   // Display the program version information and exit the program
  3167.   if(argc >= 2) {
  3168.     if(strcmp(argv[1], "version") == 0) Version();
  3169.   }
  3170.  
  3171.   char *FileName;
  3172.   char *CurrentCfgFile;
  3173.   char *CfgFile;
  3174.   Config *CfgData = new Config;
  3175.   char *AdminUser = 0;
  3176.   
  3177.   // Look for CfgFile name in environment
  3178.   if((CurrentCfgFile = getenv(EnvSetting)) == 0)
  3179.      CfgFile = (char *)DefaultCfgFile;
  3180.   else
  3181.     CfgFile = CurrentCfgFile;
  3182.  
  3183.   // Use default file name if no file is specifed on command line
  3184.   if(argc < 2) {
  3185.     int FileStatus = CfgData->Load((char *)CfgFile);
  3186.     if(!FileStatus) {
  3187.        printf("\nCannot locate any database files!\n");
  3188.        exit(0);
  3189.     }
  3190.     else {
  3191.       FileName = CfgData->GetStrValue("DBFileName");
  3192. // *********************************************************** //
  3193. // Add config file entries needed to initialize the program 
  3194. // *********************************************************** //
  3195.       FileName = CfgData->GetStrValue("DBFileName");
  3196.       AdminUser = CfgData->GetStrValue("AdminUser");
  3197. // *********************************************************** //
  3198.       if(!FileName) {
  3199.        printf("\nDBFileName section missing in config file: %s\n", CfgFile);
  3200.        exit(0);
  3201.       }
  3202.     }
  3203.   }
  3204.   else {
  3205.     FileName = argv[1];
  3206.   }
  3207.  
  3208.   if(!AdminUser) {
  3209.     AdminRights = 0;
  3210.   }
  3211.   else {
  3212.     int result = strcmp(AdminUser, "TRUE");
  3213.     if(result == 0) {
  3214.       AdminRights = 1;
  3215.     }
  3216.     else {
  3217.       AdminRights = 0;
  3218.     }
  3219.   }
  3220.  
  3221.   CfgData->UnLoad(); // Unload the Config file from memory
  3222.  
  3223.   // Initialize global database pointer
  3224.   // NOTE: Index file and data file will share the same file name
  3225.   // with different file extensions. The data file will have a 
  3226.   // .pod extension and the index file will have a .btx extension.
  3227.   if(AdminRights == 1) 
  3228.     DB = new POD(FileName, RWMode, 1, CacheSize);
  3229.   else
  3230.     DB = new POD(FileName, ROMode, 1, CacheSize);
  3231.  
  3232.   terminal->init();
  3233.   MainMenu();
  3234.   terminal->finish();
  3235.   delete DB;
  3236.   return 0;
  3237. }
  3238. // ----------------------------------------------------------- //
  3239. // ------------------------------- //
  3240. // --------- End of File --------- //
  3241. // ------------------------------- //
  3242.